LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH] i2c: cyttsp i2c touchscreen driver init submit
       [not found] <Kevin McNeely <kev@cypress.com>
@ 2010-07-12 20:56 ` Kevin McNeely
  2010-07-13  2:34   ` Christoph Fritz
                     ` (2 more replies)
  2010-08-05 18:12 ` [PATCH] i2c: cyttsp i2c and spi " Kevin McNeely
                   ` (12 subsequent siblings)
  13 siblings, 3 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-07-12 20:56 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Fred, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Mark Brown, Simtec Linux Team,
	Arnaud Patard, Antonio Ospite, Henrik Rydberg, linux-input,
	linux-kernel

From: Fred <fwk@ubuntu.linuxcertified.com>

This is a new touchscreen driver for the Cypress Semiconductor
cyttsp family of devices.  This driver is for the i2c version
of cyttsp parts.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Kconfig      |   13 +
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/cyttsp-i2c.c | 2016 ++++++++++++++++++++++++++++++++
 include/linux/cyttsp.h                 |  649 ++++++++++
 4 files changed, 2679 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp-i2c.c
 create mode 100644 include/linux/cyttsp.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3b9d5e2..a7a69a0 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
 	  To compile this driver as a module, choose M here: the
 	  module will be called tps6507x_ts.
 
+config TOUCHSCREEN_CYTTSP_I2C
+	default n
+	tristate "Cypress TTSP i2c touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system's i2c bus.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_i2c.
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 497964a..2026cb8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -47,3 +47,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp-i2c.o
diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
new file mode 100644
index 0000000..8397aa1
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp-i2c.c
@@ -0,0 +1,2016 @@
+/* Source for:
+ * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
+ * drivers/input/touchscreen/cyttsp-i2c.c
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Cypress reserves the right to make changes without further notice
+ * to the materials described herein. Cypress does not assume any
+ * liability arising out of the application described herein.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/byteorder/generic.h>
+#include <linux/bitops.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+#define CY_DECLARE_GLOBALS
+
+#include <linux/cyttsp.h>
+
+uint32_t cyttsp_tsdebug1 = 0xff;
+module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
+
+/* CY TTSP I2C Driver private data */
+struct cyttsp {
+	struct i2c_client *client;
+	struct input_dev *input;
+	struct work_struct work;
+	struct timer_list timer;
+	struct mutex mutex;
+	char phys[32];
+	struct cyttsp_platform_data *platform_data;
+	u8 num_prv_st_tch;
+	u16 act_trk[CY_NUM_TRK_ID];
+	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
+	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
+	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
+	atomic_t irq_enabled;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+};
+static u8 irq_cnt;		/* comparison counter with register valuw */
+static u32 irq_cnt_total;	/* total interrupts */
+static u32 irq_err_cnt;		/* count number of touch interrupts with err */
+#define CY_IRQ_CNT_MASK	0x000000FF	/* mapped for sizeof count in reg */
+#define CY_IRQ_CNT_REG	0x00		/* tt_undef[0]=reg 0x1B - Gen3 only */
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cyttsp_early_suspend(struct early_suspend *handler);
+static void cyttsp_late_resume(struct early_suspend *handler);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+static struct workqueue_struct *cyttsp_ts_wq;
+
+
+/* ****************************************************************************
+ * Prototypes for static functions
+ * ************************************************************************** */
+static void cyttsp_xy_worker(struct work_struct *work);
+static irqreturn_t cyttsp_irq(int irq, void *handle);
+static int cyttsp_inlist(u16 prev_track[],
+			u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
+static int cyttsp_next_avail_inlist(u16 cur_trk[],
+			u8 *new_loc, u8 num_touches);
+static int cyttsp_putbl(struct cyttsp *ts, int show,
+			int show_status, int show_version, int show_cid);
+static int __devinit cyttsp_probe(struct i2c_client *client,
+			const struct i2c_device_id *id);
+static int __devexit cyttsp_remove(struct i2c_client *client);
+static int cyttsp_resume(struct i2c_client *client);
+static int cyttsp_suspend(struct i2c_client *client, pm_message_t message);
+
+/* Static variables */
+static struct cyttsp_gen3_xydata_t g_xy_data;
+static struct cyttsp_bootloader_data_t g_bl_data;
+static struct cyttsp_sysinfo_data_t g_sysinfo_data;
+static const struct i2c_device_id cyttsp_id[] = {
+	{ CY_I2C_NAME, 0 },  { }
+};
+static u8 bl_cmd[] = {
+	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
+	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
+	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
+	CY_BL_KEY6, CY_BL_KEY7};
+
+MODULE_DEVICE_TABLE(i2c, cyttsp_id);
+
+static struct i2c_driver cyttsp_driver = {
+	.driver = {
+		.name = CY_I2C_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_probe,
+	.remove = __devexit_p(cyttsp_remove),
+	.suspend = cyttsp_suspend,
+	.resume = cyttsp_resume,
+	.id_table = cyttsp_id,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver");
+MODULE_AUTHOR("Cypress");
+
+static ssize_t cyttsp_irq_status(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct cyttsp *ts = i2c_get_clientdata(client);
+	return sprintf(buf, "%u\n", atomic_read(&ts->irq_enabled));
+}
+
+static ssize_t cyttsp_irq_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+	struct cyttsp *ts = i2c_get_clientdata(client);
+	int err = 0;
+	unsigned long value;
+
+	if (size > 2)
+		return -EINVAL;
+
+	err = strict_strtoul(buf, 10, &value);
+	if (err != 0)
+		return err;
+
+	switch (value) {
+	case 0:
+		if (atomic_cmpxchg(&ts->irq_enabled, 1, 0)) {
+			pr_info("touch irq disabled!\n");
+			disable_irq_nosync(ts->client->irq);
+		}
+		err = size;
+		break;
+	case 1:
+		if (!atomic_cmpxchg(&ts->irq_enabled, 0, 1)) {
+			pr_info("touch irq enabled!\n");
+			enable_irq(ts->client->irq);
+		}
+		err = size;
+		break;
+	default:
+		pr_info("cyttsp_irq_enable failed -> irq_enabled = %d\n",
+		atomic_read(&ts->irq_enabled));
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static DEVICE_ATTR(irq_enable, 0777, cyttsp_irq_status, cyttsp_irq_enable);
+
+/* The cyttsp_xy_worker function reads the XY coordinates and sends them to
+ * the input layer.  It is scheduled from the interrupt (or timer).
+ */
+void cyttsp_xy_worker(struct work_struct *work)
+{
+	struct cyttsp *ts = container_of(work, struct cyttsp, work);
+	u8 id, tilt, rev_x, rev_y;
+	u8 i, loc;
+	u8 prv_tch;		/* number of previous touches */
+	u8 cur_tch;	/* number of current touches */
+	u16 tmp_trk[CY_NUM_MT_TCH_ID];
+	u16 snd_trk[CY_NUM_MT_TCH_ID];
+	u16 cur_trk[CY_NUM_TRK_ID];
+	u16 cur_st_tch[CY_NUM_ST_TCH_ID];
+	u16 cur_mt_tch[CY_NUM_MT_TCH_ID];
+	/* if NOT CY_USE_TRACKING_ID then
+	 * only uses CY_NUM_MT_TCH_ID positions */
+	u16 cur_mt_pos[CY_NUM_TRK_ID][2];
+	/* if NOT CY_USE_TRACKING_ID then
+	 * only uses CY_NUM_MT_TCH_ID positions */
+	u8 cur_mt_z[CY_NUM_TRK_ID];
+	u8 curr_tool_width;
+	u16 st_x1, st_y1;
+	u8 st_z1;
+	u16 st_x2, st_y2;
+	u8 st_z2;
+	s32 retval;
+
+	cyttsp_xdebug("TTSP worker start 1:\n");
+
+	/* get event data from CYTTSP device */
+	i = CY_NUM_RETRY;
+	do {
+		retval = i2c_smbus_read_i2c_block_data(ts->client,
+			CY_REG_BASE,
+			sizeof(struct cyttsp_gen3_xydata_t), (u8 *)&g_xy_data);
+	} while ((retval < CY_OK) && --i);
+
+	if (retval < CY_OK) {
+		/* return immediately on
+		 * failure to read device on the i2c bus */
+		goto exit_xy_worker;
+	}
+
+	cyttsp_xdebug("TTSP worker start 2:\n");
+
+	/* compare own irq counter with the device irq counter */
+	if (ts->client->irq) {
+		u8 host_reg;
+		u8 cur_cnt;
+		if (ts->platform_data->use_hndshk) {
+
+			host_reg = g_xy_data.hst_mode & CY_HNDSHK_BIT ?
+				g_xy_data.hst_mode & ~CY_HNDSHK_BIT :
+				g_xy_data.hst_mode | CY_HNDSHK_BIT;
+			retval = i2c_smbus_write_i2c_block_data(ts->client,
+				CY_REG_BASE, sizeof(host_reg), &host_reg);
+		}
+		cur_cnt = g_xy_data.tt_undef[CY_IRQ_CNT_REG];
+		irq_cnt_total++;
+		irq_cnt++;
+		if (irq_cnt != cur_cnt) {
+			irq_err_cnt++;
+			cyttsp_debug("i_c_ER: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
+				irq_cnt, \
+				cur_cnt, g_xy_data.hst_mode, \
+				(unsigned long)irq_cnt_total, \
+				(unsigned long)irq_err_cnt);
+		} else {
+			cyttsp_debug("i_c_ok: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
+				irq_cnt, \
+				cur_cnt, g_xy_data.hst_mode, \
+				(unsigned long)irq_cnt_total, \
+				(unsigned long)irq_err_cnt);
+		}
+		irq_cnt = cur_cnt;
+	}
+
+	/* Get the current num touches and return if there are no touches */
+	if ((GET_BOOTLOADERMODE(g_xy_data.tt_mode) == 1) ||
+		(GET_HSTMODE(g_xy_data.hst_mode) != CY_OK)) {
+		u8 host_reg, tries;
+		/* the TTSP device has suffered spurious reset or mode switch */
+		cyttsp_debug( \
+			"Spurious err opmode (tt_mode=%02X hst_mode=%02X)\n", \
+			g_xy_data.tt_mode, g_xy_data.hst_mode);
+		cyttsp_debug("Reset TTSP Device; Terminating active tracks\n");
+		/* terminate all active tracks */
+		cur_tch = CY_NTCH;
+		/* reset TTSP part and take it back out of Bootloader mode */
+		host_reg = CY_SOFT_RESET_MODE;
+		retval = i2c_smbus_write_i2c_block_data(ts->client,
+			CY_REG_BASE,
+			sizeof(host_reg), &host_reg);
+		tries = 0;
+		do {
+			mdelay(1000);
+
+			/* set arg2 to non-0 to activate */
+			retval = cyttsp_putbl(ts, 1, false, false, false);
+		} while (!(retval < CY_OK) &&
+			!GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
+			!(g_bl_data.bl_file ==
+			CY_OP_MODE + CY_LOW_PWR_MODE) &&
+			tries++ < 10);
+		/* switch back to operational mode */
+		if (GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
+			retval = i2c_smbus_write_i2c_block_data(ts->client,
+				CY_REG_BASE,
+				sizeof(bl_cmd), bl_cmd);
+			tries = 0;
+			do {
+				mdelay(1000);
+				cyttsp_putbl(ts, 1, false, false, false);
+			} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
+				tries++ < 10);
+		}
+		if (!(retval < CY_OK)) {
+			host_reg = CY_OP_MODE
+				/* + CY_LOW_PWR_MODE */;
+			retval = i2c_smbus_write_i2c_block_data(ts->client,
+				CY_REG_BASE,
+				sizeof(host_reg), &host_reg);
+			/* wait for TTSP Device to complete switch to Op mode */
+			mdelay(1000);
+		}
+		goto exit_xy_worker;
+	} else {
+		cur_tch = GET_NUM_TOUCHES(g_xy_data.tt_stat);
+		if (IS_LARGE_AREA(g_xy_data.tt_stat)) {
+			/* terminate all active tracks */
+			cur_tch = CY_NTCH;
+			cyttsp_debug("Large obj detect (tt_stat=0x%02X). Terminate act trks\n", \
+			    g_xy_data.tt_stat);
+		} else if (cur_tch > CY_NUM_MT_TCH_ID) {
+			/* if the number of fingers on the touch surface
+			 * is more than the maximum then
+			 * there will be no new track information
+			 * even for the original touches.
+			 * Therefore, terminate all active tracks.
+			 */
+			cur_tch = CY_NTCH;
+			cyttsp_debug("Num touch err (tt_stat=0x%02X). Terminate act trks\n", \
+			    g_xy_data.tt_stat);
+		}
+	}
+
+	/* set tool size */
+	curr_tool_width = CY_SMALL_TOOL_WIDTH;
+
+	/* translate Gen2 interface data into comparable Gen3 data */
+	if (ts->platform_data->gen == CY_GEN2) {
+		struct cyttsp_gen2_xydata_t *pxy_gen2_data;
+		pxy_gen2_data = (struct cyttsp_gen2_xydata_t *)(&g_xy_data);
+
+		/* use test data? */
+		cyttsp_testdat(&g_xy_data, &tt_gen2_testray, \
+			sizeof(struct cyttsp_gen3_xydata_t));
+
+		if (pxy_gen2_data->evnt_idx == CY_GEN2_NOTOUCH) {
+			cur_tch = 0;
+		} else if (cur_tch == CY_GEN2_GHOST) {
+			cur_tch = 0;
+		} else if (cur_tch == CY_GEN2_2TOUCH) {
+			/* stuff artificial track ID1 and ID2 */
+			g_xy_data.touch12_id = 0x12;
+			g_xy_data.z1 = CY_MAXZ;
+			g_xy_data.z2 = CY_MAXZ;
+			cur_tch--;			/* 2 touches */
+		} else if (cur_tch == CY_GEN2_1TOUCH) {
+			/* stuff artificial track ID1 and ID2 */
+			g_xy_data.touch12_id = 0x12;
+			g_xy_data.z1 = CY_MAXZ;
+			g_xy_data.z2 = CY_NTCH;
+			if (pxy_gen2_data->evnt_idx == CY_GEN2_TOUCH2) {
+				/* push touch 2 data into touch1
+				 * (first finger up; second finger down) */
+				/* stuff artificial track ID1 for touch2 info */
+				g_xy_data.touch12_id = 0x20;
+				/* stuff touch 1 with touch 2 coordinate data */
+				g_xy_data.x1 = g_xy_data.x2;
+				g_xy_data.y1 = g_xy_data.y2;
+			}
+		} else {
+			cur_tch = 0;
+		}
+	} else {
+		/* use test data? */
+		cyttsp_testdat(&g_xy_data, &tt_gen3_testray, \
+			sizeof(struct cyttsp_gen3_xydata_t));
+	}
+
+
+
+	/* clear current active track ID array and count previous touches */
+	for (id = 0, prv_tch = CY_NTCH;
+		id < CY_NUM_TRK_ID; id++) {
+		cur_trk[id] = CY_NTCH;
+		prv_tch += ts->act_trk[id];
+	}
+
+	/* send no events if no previous touches and no new touches */
+	if ((prv_tch == CY_NTCH) &&
+		((cur_tch == CY_NTCH) ||
+		(cur_tch > CY_NUM_MT_TCH_ID))) {
+		goto exit_xy_worker;
+	}
+
+	cyttsp_debug("prev=%d  curr=%d\n", prv_tch, cur_tch);
+
+	for (id = 0; id < CY_NUM_ST_TCH_ID; id++) {
+		/* clear current single touches array */
+		cur_st_tch[id] = CY_IGNR_TCH;
+	}
+
+	/* clear single touch positions */
+	st_x1 = CY_NTCH;
+	st_y1 = CY_NTCH;
+	st_z1 = CY_NTCH;
+	st_x2 = CY_NTCH;
+	st_y2 = CY_NTCH;
+	st_z2 = CY_NTCH;
+
+	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+		/* clear current multi-touches array and
+		 * multi-touch positions/z */
+		cur_mt_tch[id] = CY_IGNR_TCH;
+	}
+
+	if (ts->platform_data->use_trk_id) {
+		for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+			cur_mt_pos[id][CY_XPOS] = 0;
+			cur_mt_pos[id][CY_YPOS] = 0;
+			cur_mt_z[id] = 0;
+		}
+	} else {
+		for (id = 0; id < CY_NUM_TRK_ID; id++) {
+			cur_mt_pos[id][CY_XPOS] = 0;
+			cur_mt_pos[id][CY_YPOS] = 0;
+			cur_mt_z[id] = 0;
+		}
+	}
+
+	/* Determine if display is tilted */
+	if (FLIP_DATA(ts->platform_data->flags))
+		tilt = true;
+	else
+		tilt = false;
+
+	/* Check for switch in origin */
+	if (REVERSE_X(ts->platform_data->flags))
+		rev_x = true;
+	else
+		rev_x = false;
+
+	if (REVERSE_Y(ts->platform_data->flags))
+		rev_y = true;
+	else
+		rev_y = false;
+
+	if (cur_tch) {
+		struct cyttsp_gen2_xydata_t *pxy_gen2_data;
+		struct cyttsp_gen3_xydata_t *pxy_gen3_data;
+		switch (ts->platform_data->gen) {
+		case CY_GEN2: {
+			pxy_gen2_data =
+				(struct cyttsp_gen2_xydata_t *)(&g_xy_data);
+			cyttsp_xdebug("TTSP Gen2 report:\n");
+			cyttsp_xdebug("%02X %02X %02X\n", \
+				pxy_gen2_data->hst_mode, \
+				pxy_gen2_data->tt_mode, \
+				pxy_gen2_data->tt_stat);
+			cyttsp_xdebug("%04X %04X %02X  %02X\n", \
+				pxy_gen2_data->x1, \
+				pxy_gen2_data->y1, \
+				pxy_gen2_data->z1, \
+				pxy_gen2_data->evnt_idx);
+			cyttsp_xdebug("%04X %04X %02X\n", \
+				pxy_gen2_data->x2, \
+				pxy_gen2_data->y2, \
+				pxy_gen2_data->tt_undef1);
+			cyttsp_xdebug("%02X %02X %02X\n", \
+				pxy_gen2_data->gest_cnt, \
+				pxy_gen2_data->gest_id, \
+				pxy_gen2_data->gest_set);
+			break;
+		}
+		case CY_GEN3:
+		default: {
+			pxy_gen3_data =
+				(struct cyttsp_gen3_xydata_t *)(&g_xy_data);
+			cyttsp_xdebug("TTSP Gen3 report:\n");
+			cyttsp_xdebug("%02X %02X %02X\n", \
+				pxy_gen3_data->hst_mode,
+				pxy_gen3_data->tt_mode,
+				pxy_gen3_data->tt_stat);
+			cyttsp_xdebug("%04X %04X %02X  %02X", \
+				pxy_gen3_data->x1,
+				pxy_gen3_data->y1,
+				pxy_gen3_data->z1, \
+				pxy_gen3_data->touch12_id);
+			cyttsp_xdebug("%04X %04X %02X\n", \
+				pxy_gen3_data->x2, \
+				pxy_gen3_data->y2, \
+				pxy_gen3_data->z2);
+			cyttsp_xdebug("%02X %02X %02X\n", \
+				pxy_gen3_data->gest_cnt, \
+				pxy_gen3_data->gest_id, \
+				pxy_gen3_data->gest_set);
+			cyttsp_xdebug("%04X %04X %02X  %02X\n", \
+				pxy_gen3_data->x3, \
+				pxy_gen3_data->y3, \
+				pxy_gen3_data->z3, \
+				pxy_gen3_data->touch34_id);
+			cyttsp_xdebug("%04X %04X %02X\n", \
+				pxy_gen3_data->x4, \
+				pxy_gen3_data->y4, \
+				pxy_gen3_data->z4);
+			break;
+		}
+		}
+	}
+
+	/* process the touches */
+	switch (cur_tch) {
+	case 4: {
+		g_xy_data.x4 = be16_to_cpu(g_xy_data.x4);
+		g_xy_data.y4 = be16_to_cpu(g_xy_data.y4);
+		if (tilt)
+			FLIP_XY(g_xy_data.x4, g_xy_data.y4);
+
+		if (rev_x) {
+			g_xy_data.x4 =
+				INVERT_X(g_xy_data.x4, ts->platform_data->maxx);
+		}
+		if (rev_y) {
+			g_xy_data.y4 =
+				INVERT_X(g_xy_data.y4, ts->platform_data->maxy);
+		}
+		id = GET_TOUCH4_ID(g_xy_data.touch34_id);
+		if (ts->platform_data->use_trk_id) {
+			cur_mt_pos[CY_MT_TCH4_IDX][CY_XPOS] =
+				g_xy_data.x4;
+			cur_mt_pos[CY_MT_TCH4_IDX][CY_YPOS] =
+				g_xy_data.y4;
+			cur_mt_z[CY_MT_TCH4_IDX] = g_xy_data.z4;
+		} else {
+			cur_mt_pos[id][CY_XPOS] = g_xy_data.x4;
+			cur_mt_pos[id][CY_YPOS] = g_xy_data.y4;
+			cur_mt_z[id] = g_xy_data.z4;
+		}
+		cur_mt_tch[CY_MT_TCH4_IDX] = id;
+		cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
+			CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				st_x1 = g_xy_data.x4;
+				st_y1 = g_xy_data.y4;
+				st_z1 = g_xy_data.z4;
+				cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				st_x2 = g_xy_data.x4;
+				st_y2 = g_xy_data.y4;
+				st_z2 = g_xy_data.z4;
+				cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		cyttsp_xdebug("4th XYZ:% 3d,% 3d,% 3d  ID:% 2d\n\n", \
+			g_xy_data.x4, g_xy_data.y4, g_xy_data.z4, \
+			(g_xy_data.touch34_id & 0x0F));
+		/* do not break */
+	}
+	case 3: {
+		g_xy_data.x3 = be16_to_cpu(g_xy_data.x3);
+		g_xy_data.y3 = be16_to_cpu(g_xy_data.y3);
+		if (tilt)
+			FLIP_XY(g_xy_data.x3, g_xy_data.y3);
+
+		if (rev_x) {
+			g_xy_data.x3 =
+				INVERT_X(g_xy_data.x3, ts->platform_data->maxx);
+		}
+		if (rev_y) {
+			g_xy_data.y3 =
+				INVERT_X(g_xy_data.y3, ts->platform_data->maxy);
+		}
+		id = GET_TOUCH3_ID(g_xy_data.touch34_id);
+		if (ts->platform_data->use_trk_id) {
+			cur_mt_pos[CY_MT_TCH3_IDX][CY_XPOS] =
+				g_xy_data.x3;
+			cur_mt_pos[CY_MT_TCH3_IDX][CY_YPOS] =
+				g_xy_data.y3;
+			cur_mt_z[CY_MT_TCH3_IDX] = g_xy_data.z3;
+		} else {
+			cur_mt_pos[id][CY_XPOS] = g_xy_data.x3;
+			cur_mt_pos[id][CY_YPOS] = g_xy_data.y3;
+			cur_mt_z[id] = g_xy_data.z3;
+		}
+		cur_mt_tch[CY_MT_TCH3_IDX] = id;
+		cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
+			CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				st_x1 = g_xy_data.x3;
+				st_y1 = g_xy_data.y3;
+				st_z1 = g_xy_data.z3;
+				cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				st_x2 = g_xy_data.x3;
+				st_y2 = g_xy_data.y3;
+				st_z2 = g_xy_data.z3;
+				cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		cyttsp_xdebug("3rd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
+			g_xy_data.x3, g_xy_data.y3, g_xy_data.z3, \
+			((g_xy_data.touch34_id >> 4) & 0x0F));
+		/* do not break */
+	}
+	case 2: {
+		g_xy_data.x2 = be16_to_cpu(g_xy_data.x2);
+		g_xy_data.y2 = be16_to_cpu(g_xy_data.y2);
+		if (tilt)
+			FLIP_XY(g_xy_data.x2, g_xy_data.y2);
+
+		if (rev_x) {
+			g_xy_data.x2 =
+				INVERT_X(g_xy_data.x2, ts->platform_data->maxx);
+		}
+		if (rev_y) {
+			g_xy_data.y2 =
+				INVERT_X(g_xy_data.y2, ts->platform_data->maxy);
+		}
+		id = GET_TOUCH2_ID(g_xy_data.touch12_id);
+		if (ts->platform_data->use_trk_id) {
+			cur_mt_pos[CY_MT_TCH2_IDX][CY_XPOS] =
+				g_xy_data.x2;
+			cur_mt_pos[CY_MT_TCH2_IDX][CY_YPOS] =
+				g_xy_data.y2;
+			cur_mt_z[CY_MT_TCH2_IDX] = g_xy_data.z2;
+		} else {
+			cur_mt_pos[id][CY_XPOS] = g_xy_data.x2;
+			cur_mt_pos[id][CY_YPOS] = g_xy_data.y2;
+			cur_mt_z[id] = g_xy_data.z2;
+		}
+		cur_mt_tch[CY_MT_TCH2_IDX] = id;
+		cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
+			CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				st_x1 = g_xy_data.x2;
+				st_y1 = g_xy_data.y2;
+				st_z1 = g_xy_data.z2;
+				cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				st_x2 = g_xy_data.x2;
+				st_y2 = g_xy_data.y2;
+				st_z2 = g_xy_data.z2;
+				cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		cyttsp_xdebug("2nd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
+			g_xy_data.x2, g_xy_data.y2, g_xy_data.z2, \
+			(g_xy_data.touch12_id & 0x0F));
+		/* do not break */
+	}
+	case 1:	{
+		g_xy_data.x1 = be16_to_cpu(g_xy_data.x1);
+		g_xy_data.y1 = be16_to_cpu(g_xy_data.y1);
+		if (tilt)
+			FLIP_XY(g_xy_data.x1, g_xy_data.y1);
+
+		if (rev_x) {
+			g_xy_data.x1 =
+				INVERT_X(g_xy_data.x1, ts->platform_data->maxx);
+		}
+		if (rev_y) {
+			g_xy_data.y1 =
+				INVERT_X(g_xy_data.y1, ts->platform_data->maxy);
+		}
+		id = GET_TOUCH1_ID(g_xy_data.touch12_id);
+		if (ts->platform_data->use_trk_id) {
+			cur_mt_pos[CY_MT_TCH1_IDX][CY_XPOS] =
+				g_xy_data.x1;
+			cur_mt_pos[CY_MT_TCH1_IDX][CY_YPOS] =
+				g_xy_data.y1;
+			cur_mt_z[CY_MT_TCH1_IDX] = g_xy_data.z1;
+		} else {
+			cur_mt_pos[id][CY_XPOS] = g_xy_data.x1;
+			cur_mt_pos[id][CY_YPOS] = g_xy_data.y1;
+			cur_mt_z[id] = g_xy_data.z1;
+		}
+		cur_mt_tch[CY_MT_TCH1_IDX] = id;
+		cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
+			CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				st_x1 = g_xy_data.x1;
+				st_y1 = g_xy_data.y1;
+				st_z1 = g_xy_data.z1;
+				cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				st_x2 = g_xy_data.x1;
+				st_y2 = g_xy_data.y1;
+				st_z2 = g_xy_data.z1;
+				cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		cyttsp_xdebug("1st XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
+			g_xy_data.x1, g_xy_data.y1, g_xy_data.z1, \
+			((g_xy_data.touch12_id >> 4) & 0x0F));
+		break;
+	}
+	case 0:
+	default:{
+		break;
+	}
+	}
+
+	/* handle Single Touch signals */
+	if (ts->platform_data->use_st) {
+		cyttsp_xdebug("ST STEP 0 - ST1 ID=%d  ST2 ID=%d\n", \
+			cur_st_tch[CY_ST_FNGR1_IDX], \
+			cur_st_tch[CY_ST_FNGR2_IDX]);
+		if (cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) {
+			/* reassign finger 1 and 2 positions to new tracks */
+			if (cur_tch > 0) {
+				/* reassign st finger1 */
+				if (ts->platform_data->use_trk_id) {
+					id = CY_MT_TCH1_IDX;
+					cur_st_tch[CY_ST_FNGR1_IDX] = cur_mt_tch[id];
+				} else {
+					id = GET_TOUCH1_ID(g_xy_data.touch12_id);
+					cur_st_tch[CY_ST_FNGR1_IDX] = id;
+				}
+				st_x1 = cur_mt_pos[id][CY_XPOS];
+				st_y1 = cur_mt_pos[id][CY_YPOS];
+				st_z1 = cur_mt_z[id];
+				cyttsp_xdebug("ST STEP 1 - ST1 ID=%3d\n", \
+					cur_st_tch[CY_ST_FNGR1_IDX]);
+				if ((cur_tch > 1) &&
+					(cur_st_tch[CY_ST_FNGR2_IDX] >
+					CY_NUM_TRK_ID)) {
+					/* reassign st finger2 */
+					if (cur_tch > 1) {
+						if (ts->platform_data->use_trk_id) {
+							id = CY_MT_TCH2_IDX;
+							cur_st_tch[CY_ST_FNGR2_IDX] = cur_mt_tch[id];
+						} else {
+							id = GET_TOUCH2_ID(g_xy_data.touch12_id);
+							cur_st_tch[CY_ST_FNGR2_IDX] = id;
+						}
+						st_x2 = cur_mt_pos[id][CY_XPOS];
+						st_y2 = cur_mt_pos[id][CY_YPOS];
+						st_z2 = cur_mt_z[id];
+						cyttsp_xdebug("ST STEP 2 - ST2 ID=%3d\n", \
+							cur_st_tch[CY_ST_FNGR2_IDX]);
+					}
+				}
+			}
+		} else if (cur_st_tch[CY_ST_FNGR2_IDX] > CY_NUM_TRK_ID) {
+			if (cur_tch > 1) {
+				/* reassign st finger2 */
+				if (ts->platform_data->use_trk_id) {
+					/* reassign st finger2 */
+					id = CY_MT_TCH2_IDX;
+					cur_st_tch[CY_ST_FNGR2_IDX] =
+						cur_mt_tch[id];
+				} else {
+					/* reassign st finger2 */
+					id = GET_TOUCH2_ID(g_xy_data.touch12_id);
+					cur_st_tch[CY_ST_FNGR2_IDX] = id;
+				}
+				st_x2 = cur_mt_pos[id][CY_XPOS];
+				st_y2 = cur_mt_pos[id][CY_YPOS];
+				st_z2 = cur_mt_z[id];
+				cyttsp_xdebug("ST STEP 3 - ST2 ID=%3d\n", \
+					cur_st_tch[CY_ST_FNGR2_IDX]);
+			}
+		}
+		/* if the 1st touch is missing and there is a 2nd touch,
+		 * then set the 1st touch to 2nd touch and terminate 2nd touch
+		 */
+		if ((cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) &&
+		    (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID)) {
+			st_x1 = st_x2;
+			st_y1 = st_y2;
+			st_z1 = st_z2;
+			cur_st_tch[CY_ST_FNGR1_IDX] =
+				cur_st_tch[CY_ST_FNGR2_IDX];
+			cur_st_tch[CY_ST_FNGR2_IDX] =
+				CY_IGNR_TCH;
+		}
+		/* if the 2nd touch ends up equal to the 1st touch,
+		 * then just report a single touch */
+		if (cur_st_tch[CY_ST_FNGR1_IDX] ==
+			cur_st_tch[CY_ST_FNGR2_IDX]) {
+			cur_st_tch[CY_ST_FNGR2_IDX] =
+				CY_IGNR_TCH;
+		}
+		/* set Single Touch current event signals */
+		if (cur_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) {
+			input_report_abs(ts->input,
+				ABS_X, st_x1);
+			input_report_abs(ts->input,
+				ABS_Y, st_y1);
+			input_report_abs(ts->input,
+				ABS_PRESSURE, st_z1);
+			input_report_key(ts->input,
+				BTN_TOUCH,
+				CY_TCH);
+			input_report_abs(ts->input,
+				ABS_TOOL_WIDTH,
+				curr_tool_width);
+			cyttsp_debug("ST->F1:%3d X:%3d Y:%3d Z:%3d\n", \
+				cur_st_tch[CY_ST_FNGR1_IDX], \
+				st_x1, st_y1, st_z1);
+			if (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID) {
+				input_report_key(ts->input, BTN_2, CY_TCH);
+				input_report_abs(ts->input, ABS_HAT0X, st_x2);
+				input_report_abs(ts->input, ABS_HAT0Y, st_y2);
+				cyttsp_debug("ST->F2:%3d X:%3d Y:%3d Z:%3d\n", \
+					cur_st_tch[CY_ST_FNGR2_IDX],
+					st_x2, st_y2, st_z2);
+			} else {
+				input_report_key(ts->input,
+					BTN_2,
+					CY_NTCH);
+			}
+		} else {
+			input_report_abs(ts->input, ABS_PRESSURE, CY_NTCH);
+			input_report_key(ts->input, BTN_TOUCH, CY_NTCH);
+			input_report_key(ts->input, BTN_2, CY_NTCH);
+		}
+		/* update platform data for the current single touch info */
+		ts->prv_st_tch[CY_ST_FNGR1_IDX] = cur_st_tch[CY_ST_FNGR1_IDX];
+		ts->prv_st_tch[CY_ST_FNGR2_IDX] = cur_st_tch[CY_ST_FNGR2_IDX];
+
+	}
+
+	/* handle Multi-touch signals */
+	if (ts->platform_data->use_mt) {
+		if (ts->platform_data->use_trk_id) {
+			/* terminate any previous touch where the track
+			 * is missing from the current event */
+			for (id = 0; id < CY_NUM_TRK_ID; id++) {
+				if ((ts->act_trk[id] != CY_NTCH) &&
+					(cur_trk[id] == CY_NTCH)) {
+					input_report_abs(ts->input,
+						ABS_MT_TRACKING_ID,
+						id);
+					input_report_abs(ts->input,
+						ABS_MT_TOUCH_MAJOR,
+						CY_NTCH);
+					input_report_abs(ts->input,
+						ABS_MT_WIDTH_MAJOR,
+						curr_tool_width);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_X,
+						ts->prv_mt_pos[id][CY_XPOS]);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_Y,
+						ts->prv_mt_pos[id][CY_YPOS]);
+					CY_MT_SYNC(ts->input);
+					ts->act_trk[id] = CY_NTCH;
+					ts->prv_mt_pos[id][CY_XPOS] = 0;
+					ts->prv_mt_pos[id][CY_YPOS] = 0;
+				}
+			}
+			/* set Multi-Touch current event signals */
+			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+				if (cur_mt_tch[id] < CY_NUM_TRK_ID) {
+					input_report_abs(ts->input,
+						ABS_MT_TRACKING_ID,
+						cur_mt_tch[id]);
+					input_report_abs(ts->input,
+						ABS_MT_TOUCH_MAJOR,
+						cur_mt_z[id]);
+					input_report_abs(ts->input,
+						ABS_MT_WIDTH_MAJOR,
+						curr_tool_width);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_X,
+						cur_mt_pos[id][CY_XPOS]);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_Y,
+						cur_mt_pos[id][CY_YPOS]);
+					CY_MT_SYNC(ts->input);
+					ts->act_trk[id] = CY_TCH;
+					ts->prv_mt_pos[id][CY_XPOS] =
+						cur_mt_pos[id][CY_XPOS];
+					ts->prv_mt_pos[id][CY_YPOS] =
+						cur_mt_pos[id][CY_YPOS];
+				}
+			}
+		} else {
+			/* set temporary track array elements to voids */
+			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+				tmp_trk[id] = CY_IGNR_TCH;
+				snd_trk[id] = CY_IGNR_TCH;
+			}
+
+			/* get what is currently active */
+			for (i = 0, id = 0;
+				id < CY_NUM_TRK_ID && i < CY_NUM_MT_TCH_ID;
+				id++) {
+				if (cur_trk[id] == CY_TCH) {
+					/* only incr counter if track found */
+					tmp_trk[i] = id;
+					i++;
+				}
+			}
+			cyttsp_xdebug("T1: t0=%d, t1=%d, t2=%d, t3=%d\n", \
+				tmp_trk[0], tmp_trk[1], tmp_trk[2], \
+				tmp_trk[3]);
+			cyttsp_xdebug("T1: p0=%d, p1=%d, p2=%d, p3=%d\n", \
+				ts->prv_mt_tch[0], ts->prv_mt_tch[1], \
+				ts->prv_mt_tch[2], ts->prv_mt_tch[3]);
+
+			/* pack in still active previous touches */
+			for (id = 0, prv_tch = 0;
+				id < CY_NUM_MT_TCH_ID; id++) {
+				if (tmp_trk[id] < CY_NUM_TRK_ID) {
+					if (cyttsp_inlist(ts->prv_mt_tch,
+						tmp_trk[id], &loc,
+						CY_NUM_MT_TCH_ID)) {
+						loc &= CY_NUM_MT_TCH_ID - 1;
+						snd_trk[loc] = tmp_trk[id];
+						prv_tch++;
+						cyttsp_xdebug("inlist s[%d]=%d t[%d]=%d l=%d p=%d\n", \
+							loc, snd_trk[loc], \
+							id, tmp_trk[id], \
+							loc, prv_tch);
+					} else {
+						cyttsp_xdebug("not inlist s[%d]=%d t[%d]=%d l=%d \n", \
+							id, snd_trk[id], \
+							id, tmp_trk[id], \
+							loc);
+					}
+				}
+			}
+			cyttsp_xdebug("S1: s0=%d, s1=%d, s2=%d, s3=%d p=%d\n", \
+				snd_trk[0], snd_trk[1], snd_trk[2], \
+				snd_trk[3], prv_tch);
+
+			/* pack in new touches */
+			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+				if (tmp_trk[id] < CY_NUM_TRK_ID) {
+					if (!cyttsp_inlist(snd_trk, tmp_trk[id], &loc, CY_NUM_MT_TCH_ID)) {
+						cyttsp_xdebug("not inlist t[%d]=%d l=%d\n", \
+							id, tmp_trk[id], loc);
+						if (cyttsp_next_avail_inlist(snd_trk, &loc, CY_NUM_MT_TCH_ID)) {
+							loc &= CY_NUM_MT_TCH_ID - 1;
+							snd_trk[loc] = tmp_trk[id];
+							cyttsp_xdebug("put inlist s[%d]=%d t[%d]=%d\n",
+								loc, snd_trk[loc], id, tmp_trk[id]);
+						}
+					} else {
+						cyttsp_xdebug("is in list s[%d]=%d t[%d]=%d loc=%d\n", \
+							id, snd_trk[id], id, tmp_trk[id], loc);
+					}
+				}
+			}
+			cyttsp_xdebug("S2: s0=%d, s1=%d, s2=%d, s3=%d\n", \
+				snd_trk[0], snd_trk[1],
+				snd_trk[2], snd_trk[3]);
+
+			/* sync motion event signals for each current touch */
+			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+				/* z will either be 0 (NOTOUCH) or
+				 * some pressure (TOUCH) */
+				cyttsp_xdebug("MT0 prev[%d]=%d temp[%d]=%d send[%d]=%d\n", \
+					id, ts->prv_mt_tch[id], \
+					id, tmp_trk[id], \
+					id, snd_trk[id]);
+				if (snd_trk[id] < CY_NUM_TRK_ID) {
+					input_report_abs(ts->input,
+						ABS_MT_TOUCH_MAJOR,
+						cur_mt_z[snd_trk[id]]);
+					input_report_abs(ts->input,
+						ABS_MT_WIDTH_MAJOR,
+						curr_tool_width);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_X,
+						cur_mt_pos[snd_trk[id]][CY_XPOS]);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_Y,
+						cur_mt_pos[snd_trk[id]][CY_YPOS]);
+					CY_MT_SYNC(ts->input);
+					cyttsp_debug("MT1->TID:%2d X:%3d Y:%3d Z:%3d touch-sent\n", \
+						snd_trk[id], \
+						cur_mt_pos[snd_trk[id]][CY_XPOS], \
+						cur_mt_pos[snd_trk[id]][CY_YPOS], \
+						cur_mt_z[snd_trk[id]]);
+				} else if (ts->prv_mt_tch[id] < CY_NUM_TRK_ID) {
+					/* void out this touch */
+					input_report_abs(ts->input,
+						ABS_MT_TOUCH_MAJOR,
+						CY_NTCH);
+					input_report_abs(ts->input,
+						ABS_MT_WIDTH_MAJOR,
+						curr_tool_width);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_X,
+						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS]);
+					input_report_abs(ts->input,
+						ABS_MT_POSITION_Y,
+						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS]);
+					CY_MT_SYNC(ts->input);
+					cyttsp_debug("MT2->TID:%2d X:%3d Y:%3d Z:%3d lift off-sent\n", \
+						ts->prv_mt_tch[id], \
+						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS], \
+						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS], \
+						CY_NTCH);
+				} else {
+					/* do not stuff any signals for this
+					 * previously and currently
+					 * void touches */
+					cyttsp_xdebug("MT3->send[%d]=%d - No touch - NOT sent\n", \
+							id, snd_trk[id]);
+				}
+			}
+
+			/* save current posted tracks to
+			 * previous track memory */
+			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+				ts->prv_mt_tch[id] = snd_trk[id];
+				ts->prv_mt_pos[snd_trk[id]][CY_XPOS] =
+					cur_mt_pos[snd_trk[id]][CY_XPOS];
+				ts->prv_mt_pos[snd_trk[id]][CY_YPOS] =
+					cur_mt_pos[snd_trk[id]][CY_YPOS];
+				cyttsp_xdebug("MT4->TID:%2d X:%3d Y:%3d Z:%3d save for previous\n", \
+					snd_trk[id], \
+					ts->prv_mt_pos[snd_trk[id]][CY_XPOS], \
+					ts->prv_mt_pos[snd_trk[id]][CY_YPOS], \
+					CY_NTCH);
+			}
+			for (id = 0; id < CY_NUM_TRK_ID; id++)
+				ts->act_trk[id] = CY_NTCH;
+			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+				if (snd_trk[id] < CY_NUM_TRK_ID)
+					ts->act_trk[snd_trk[id]] = CY_TCH;
+			}
+		}
+	}
+
+	/* handle gestures */
+	if (ts->platform_data->use_gestures) {
+		if (g_xy_data.gest_id) {
+			input_report_key(ts->input,
+				BTN_3, CY_TCH);
+			input_report_abs(ts->input,
+				ABS_HAT1X, g_xy_data.gest_id);
+			input_report_abs(ts->input,
+				ABS_HAT2Y, g_xy_data.gest_cnt);
+		}
+	}
+
+	/* signal the view motion event */
+	input_sync(ts->input);
+
+	for (id = 0; id < CY_NUM_TRK_ID; id++) {
+		/* update platform data for the current MT information */
+		ts->act_trk[id] = cur_trk[id];
+	}
+
+exit_xy_worker:
+	if (cyttsp_disable_touch) {
+		/* Turn off the touch interrupts */
+		cyttsp_debug("Not enabling touch\n");
+	} else {
+		if (ts->client->irq == 0) {
+			/* restart event timer */
+			mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
+		} else {
+			/* re-enable the interrupt after processing */
+			enable_irq(ts->client->irq);
+		}
+	}
+	return;
+}
+
+static int cyttsp_inlist(u16 prev_track[], u8 cur_trk_id,
+			u8 *prev_loc, u8 num_touches)
+{
+	u8 id = 0;
+
+	*prev_loc = CY_IGNR_TCH;
+
+		cyttsp_xdebug("IN p[%d]=%d c=%d n=%d loc=%d\n", \
+			id, prev_track[id], cur_trk_id, \
+			num_touches, *prev_loc);
+	for (id = 0, *prev_loc = CY_IGNR_TCH;
+		(id < num_touches); id++) {
+		cyttsp_xdebug("p[%d]=%d c=%d n=%d loc=%d\n", \
+			id, prev_track[id], cur_trk_id, \
+			num_touches, *prev_loc);
+		if (prev_track[id] == cur_trk_id) {
+			*prev_loc = id;
+			break;
+		}
+	}
+	cyttsp_xdebug("OUT p[%d]=%d c=%d n=%d loc=%d\n", \
+		id, prev_track[id], cur_trk_id, num_touches, *prev_loc);
+
+	return ((*prev_loc < CY_NUM_TRK_ID) ? true : false);
+}
+
+static int cyttsp_next_avail_inlist(u16 cur_trk[],
+			u8 *new_loc, u8 num_touches)
+{
+	u8 id;
+
+	for (id = 0, *new_loc = CY_IGNR_TCH;
+		(id < num_touches); id++) {
+		if (cur_trk[id] > CY_NUM_TRK_ID) {
+			*new_loc = id;
+			break;
+		}
+	}
+
+	return ((*new_loc < CY_NUM_TRK_ID) ? true : false);
+}
+
+/* Timer function used as dummy interrupt driver */
+static void cyttsp_timer(unsigned long handle)
+{
+	struct cyttsp *ts = (struct cyttsp *) handle;
+
+	cyttsp_xdebug("TTSP Device timer event\n");
+
+	/* schedule motion signal handling */
+	queue_work(cyttsp_ts_wq, &ts->work);
+
+	return;
+}
+
+
+
+/* ************************************************************************
+ * ISR function. This function is general, initialized in drivers init
+ * function
+ * ************************************************************************ */
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = (struct cyttsp *) handle;
+
+	cyttsp_xdebug("%s: Got IRQ\n", CY_I2C_NAME);
+
+	/* disable further interrupts until this interrupt is processed */
+	disable_irq_nosync(ts->client->irq);
+
+	/* schedule motion signal handling */
+	queue_work(cyttsp_ts_wq, &ts->work);
+	return IRQ_HANDLED;
+}
+
+/* ************************************************************************
+ * Probe initialization functions
+ * ************************************************************************ */
+static int cyttsp_putbl(struct cyttsp *ts, int show,
+			int show_status, int show_version, int show_cid)
+{
+	int retval = CY_OK;
+
+	int num_bytes = (show_status * 3) + (show_version * 6) + (show_cid * 3);
+
+	if (show_cid)
+		num_bytes = sizeof(struct cyttsp_bootloader_data_t);
+	else if (show_version)
+		num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 3;
+	else
+		num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 9;
+
+	if (show) {
+		retval = i2c_smbus_read_i2c_block_data(ts->client,
+			CY_REG_BASE, num_bytes, (u8 *)&g_bl_data);
+		if (show_status) {
+			cyttsp_debug("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X\n", \
+				show, \
+				g_bl_data.bl_file, \
+				g_bl_data.bl_status, \
+				g_bl_data.bl_error, \
+				g_bl_data.blver_hi, g_bl_data.blver_lo, \
+				g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo);
+		}
+		if (show_version) {
+			cyttsp_debug("BL%d: ttspver=0x%02X%02X appid=0x%02X%02X appver=0x%02X%02X\n", \
+				show, \
+				g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
+				g_bl_data.appid_hi, g_bl_data.appid_lo, \
+				g_bl_data.appver_hi, g_bl_data.appver_lo);
+		}
+		if (show_cid) {
+			cyttsp_debug("BL%d: cid=0x%02X%02X%02X\n", \
+				show, \
+				g_bl_data.cid_0, \
+				g_bl_data.cid_1, \
+				g_bl_data.cid_2);
+		}
+		mdelay(CY_DLY_DFLT);
+	}
+
+	return retval;
+}
+
+#ifdef CY_INCLUDE_LOAD_FILE
+#define CY_MAX_I2C_LEN	256
+#define CY_MAX_TRY		10
+#define CY_BL_PAGE_SIZE	16
+#define CY_BL_NUM_PAGES	5
+static int cyttsp_i2c_wr_blk_data(struct i2c_client *client, u8 command,
+			       u8 length, const u8 *values)
+{
+	int retval = CY_OK;
+
+	u8 dataray[CY_MAX_I2C_LEN];
+	u8 try;
+	dataray[0] = command;
+	if (length)
+		memcpy(&dataray[1], values, length);
+
+	try = CY_MAX_TRY;
+	do {
+		retval = i2c_master_send(client, dataray, length+1);
+		mdelay(CY_DLY_DFLT*2);
+	} while ((retval != length+1) && try--);
+
+	return retval;
+}
+
+static int cyttsp_i2c_wr_blk_chunks(struct cyttsp *ts, u8 command,
+			       u8 length, const u8 *values)
+{
+	int retval = CY_OK;
+	int block = 1;
+
+	u8 dataray[CY_MAX_I2C_LEN];
+
+	/* first page already includes the bl page offset */
+	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
+		CY_BL_PAGE_SIZE+1, values);
+	mdelay(10);
+	values += CY_BL_PAGE_SIZE+1;
+	length -= CY_BL_PAGE_SIZE+1;
+
+	/* rem blocks require bl page offset stuffing */
+	while (length &&
+		(block < CY_BL_NUM_PAGES) &&
+		!(retval < CY_OK)) {
+		dataray[0] = CY_BL_PAGE_SIZE*block;
+		memcpy(&dataray[1], values,
+			length >= CY_BL_PAGE_SIZE ?
+			CY_BL_PAGE_SIZE : length);
+		retval = i2c_smbus_write_i2c_block_data(ts->client,
+			CY_REG_BASE,
+			length >= CY_BL_PAGE_SIZE ?
+			CY_BL_PAGE_SIZE + 1 : length+1, dataray);
+		mdelay(10);
+		values += CY_BL_PAGE_SIZE;
+		length = length >= CY_BL_PAGE_SIZE ?
+			length - CY_BL_PAGE_SIZE : 0;
+		block++;
+	}
+
+	return retval;
+}
+
+static int cyttsp_bootload_app(struct cyttsp *ts)
+{
+	int retval = CY_OK;
+	int i, tries;
+	u8 host_reg;
+
+	cyttsp_debug("load new firmware \n");
+	/* reset TTSP Device back to bootloader mode */
+	host_reg = CY_SOFT_RESET_MODE;
+	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
+		sizeof(host_reg), &host_reg);
+	/* wait for TTSP Device to complete reset back to bootloader */
+	mdelay(1000);
+	cyttsp_putbl(ts, 3, true, true, true);
+	cyttsp_debug("load file - tver=0x%02X%02X a_id=0x%02X%02X aver=0x%02X%02X\n", \
+		cyttsp_fw_tts_verh, cyttsp_fw_tts_verl, \
+		cyttsp_fw_app_idh, cyttsp_fw_app_idl, \
+		cyttsp_fw_app_verh, cyttsp_fw_app_verl);
+
+	/* download new TTSP Application to the Bootloader */
+	if (!(retval < CY_OK)) {
+		i = 0;
+		/* send bootload initiation command */
+		if (cyttsp_fw[i].Command == CY_BL_INIT_LOAD) {
+			g_bl_data.bl_file = 0;
+			g_bl_data.bl_status = 0;
+			g_bl_data.bl_error = 0;
+			retval = i2c_smbus_write_i2c_block_data(ts->client,
+				CY_REG_BASE,
+				cyttsp_fw[i].Length, cyttsp_fw[i].Block);
+			/* delay to allow bl to get ready for block writes */
+			i++;
+			tries = 0;
+			cyttsp_debug("wait init f=%02X, s=%02X, e=%02X t=%d\n", \
+				g_bl_data.bl_file, g_bl_data.bl_status, \
+				g_bl_data.bl_error, tries);
+			do {
+				mdelay(1000);
+				cyttsp_putbl(ts, 4, true, false, false);
+			} while (g_bl_data.bl_status != 0x10 &&
+				g_bl_data.bl_status != 0x11 &&
+				tries++ < 10);
+			/* send bootload firmware load blocks */
+			if (!(retval < CY_OK)) {
+				while (cyttsp_fw[i].Command == CY_BL_WRITE_BLK) {
+					retval = cyttsp_i2c_wr_blk_chunks(ts,
+						CY_REG_BASE,
+						cyttsp_fw[i].Length,
+						cyttsp_fw[i].Block);
+					/* bl requires dly after blocks */
+					mdelay(100);
+					cyttsp_debug("BL DNLD Rec=% 3d Len=% 3d Addr=%04X\n", \
+						cyttsp_fw[i].Record, \
+						cyttsp_fw[i].Length, \
+						cyttsp_fw[i].Address);
+					i++;
+					if (retval < CY_OK) {
+						cyttsp_debug("BL fail Rec=%3d retval=%d\n", \
+							cyttsp_fw[i-1].Record, \
+							retval);
+						break;
+					} else {
+						/* reset TTSP I2C counter */
+						retval = cyttsp_i2c_wr_blk_data(ts->client,
+							CY_REG_BASE,
+							0, NULL);
+						mdelay(10);
+						cyttsp_putbl(ts, 5,
+							true, false, false);
+					}
+				}
+				if (!(retval < CY_OK)) {
+					while (i < cyttsp_fw_records) {
+						retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
+							cyttsp_fw[i].Length,
+							cyttsp_fw[i].Block);
+						i++;
+						tries = 0;
+						cyttsp_debug("wait init f=%02X, s=%02X, e=%02X t=%d\n", \
+							g_bl_data.bl_file, \
+							g_bl_data.bl_status, \
+							g_bl_data.bl_error, \
+							tries);
+						do {
+							mdelay(1000);
+							cyttsp_putbl(ts, 6, true, false, false);
+						} while (g_bl_data.bl_status != 0x10 &&
+							g_bl_data.bl_status != 0x11 &&
+							tries++ < 10);
+						cyttsp_putbl(ts, 7, true, false,
+							false);
+						if (retval < CY_OK)
+							break;
+					}
+				}
+			}
+		}
+	}
+
+	/* reset TTSP Device back to bootloader mode */
+	host_reg = CY_SOFT_RESET_MODE;
+	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
+		sizeof(host_reg), &host_reg);
+	/* wait for TTSP Device to complete reset back to bootloader */
+	mdelay(1000);
+
+	/* set arg2 to non-0 to activate */
+	retval = cyttsp_putbl(ts, 8, true, true, true);
+
+	return retval;
+}
+#else
+static int cyttsp_bootload_app(struct cyttsp *ts)
+{
+	cyttsp_debug("no-load new firmware \n");
+	return CY_OK;
+}
+#endif /* CY_INCLUDE_LOAD_FILE */
+
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+	int retval = CY_OK;
+	u8 host_reg;
+	int tries;
+
+	cyttsp_debug("Power up \n");
+
+	/* check if the TTSP device has a bootloader installed */
+	host_reg = CY_SOFT_RESET_MODE;
+	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
+		sizeof(host_reg), &host_reg);
+	tries = 0;
+	do {
+		mdelay(1000);
+
+		/* set arg2 to non-0 to activate */
+		retval = cyttsp_putbl(ts, 1, true, true, true);
+		cyttsp_info("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X R=%d\n", \
+			101, \
+			g_bl_data.bl_file, g_bl_data.bl_status, \
+			g_bl_data.bl_error, \
+			g_bl_data.blver_hi, g_bl_data.blver_lo, \
+			g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo,
+			retval);
+		cyttsp_info("BL%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
+			102, \
+			g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
+			g_bl_data.appid_hi, g_bl_data.appid_lo, \
+			g_bl_data.appver_hi, g_bl_data.appver_lo);
+		cyttsp_info("BL%d: c_id=%02X%02X%02X\n", \
+			103, \
+			g_bl_data.cid_0, g_bl_data.cid_1, g_bl_data.cid_2);
+	} while (!(retval < CY_OK) &&
+		!GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
+		!(g_bl_data.bl_file == CY_OP_MODE + CY_LOW_PWR_MODE) &&
+		tries++ < 10);
+
+	/* is bootloader missing? */
+	if (!(retval < CY_OK)) {
+		cyttsp_xdebug("Ret=%d  Check if bootloader is missing...\n", \
+			retval);
+		if (!GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
+			/* skip all bl and sys info and go to op mode */
+			if (!(retval < CY_OK)) {
+				cyttsp_xdebug("Bl is missing (ret=%d)\n", \
+					retval);
+				host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
+				retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
+					sizeof(host_reg), &host_reg);
+				/* wait for TTSP Device to complete switch to
+				 * Operational mode */
+				mdelay(1000);
+				goto bypass;
+			}
+		}
+	}
+
+
+	/* take TTSP out of bootloader mode; go to TrueTouch operational mode */
+	if (!(retval < CY_OK)) {
+		cyttsp_xdebug1("exit bootloader; go operational\n");
+		retval = i2c_smbus_write_i2c_block_data(ts->client,
+			CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
+		tries = 0;
+		do {
+			mdelay(1000);
+			cyttsp_putbl(ts, 4, true, false, false);
+			cyttsp_info("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X\n", \
+				104, \
+				g_bl_data.bl_file, g_bl_data.bl_status, \
+				g_bl_data.bl_error, \
+				g_bl_data.blver_hi, g_bl_data.blver_lo, \
+				g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo);
+		} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
+			tries++ < 10);
+	}
+
+
+
+	if (!(retval < CY_OK) &&
+		cyttsp_app_load()) {
+		mdelay(1000);
+		if (CY_DIFF(g_bl_data.ttspver_hi, cyttsp_tts_verh())  ||
+			CY_DIFF(g_bl_data.ttspver_lo, cyttsp_tts_verl())  ||
+			CY_DIFF(g_bl_data.appid_hi, cyttsp_app_idh())  ||
+			CY_DIFF(g_bl_data.appid_lo, cyttsp_app_idl())  ||
+			CY_DIFF(g_bl_data.appver_hi, cyttsp_app_verh())  ||
+			CY_DIFF(g_bl_data.appver_lo, cyttsp_app_verl())  ||
+			CY_DIFF(g_bl_data.cid_0, cyttsp_cid_0())  ||
+			CY_DIFF(g_bl_data.cid_1, cyttsp_cid_1())  ||
+			CY_DIFF(g_bl_data.cid_2, cyttsp_cid_2())  ||
+			cyttsp_force_fw_load()) {
+			cyttsp_debug("blttsp=0x%02X%02X flttsp=0x%02X%02X force=%d\n", \
+				g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
+				cyttsp_tts_verh(), cyttsp_tts_verl(), \
+				cyttsp_force_fw_load());
+			cyttsp_debug("blappid=0x%02X%02X flappid=0x%02X%02X\n", \
+				g_bl_data.appid_hi, g_bl_data.appid_lo, \
+				cyttsp_app_idh(), cyttsp_app_idl());
+			cyttsp_debug("blappver=0x%02X%02X flappver=0x%02X%02X\n", \
+				g_bl_data.appver_hi, g_bl_data.appver_lo, \
+				cyttsp_app_verh(), cyttsp_app_verl());
+			cyttsp_debug("blcid=0x%02X%02X%02X flcid=0x%02X%02X%02X\n", \
+				g_bl_data.cid_0, \
+				g_bl_data.cid_1, \
+				g_bl_data.cid_2, \
+				cyttsp_cid_0(), \
+				cyttsp_cid_1(), \
+				cyttsp_cid_2());
+			/* enter bootloader to load new app into TTSP Device */
+			retval = cyttsp_bootload_app(ts);
+			/* take TTSP device out of bootloader mode;
+			 * switch back to TrueTouch operational mode */
+			if (!(retval < CY_OK)) {
+				retval = i2c_smbus_write_i2c_block_data(ts->client,
+					CY_REG_BASE,
+					sizeof(bl_cmd), bl_cmd);
+				/* wait for TTSP Device to complete
+				 * switch to Operational mode */
+				mdelay(1000);
+			}
+		}
+	}
+
+bypass:
+	/* switch to System Information mode to read versions
+	 * and set interval registers */
+	if (!(retval < CY_OK)) {
+		cyttsp_debug("switch to sysinfo mode \n");
+		host_reg = CY_SYSINFO_MODE;
+		retval = i2c_smbus_write_i2c_block_data(ts->client,
+			CY_REG_BASE, sizeof(host_reg), &host_reg);
+		/* wait for TTSP Device to complete switch to SysInfo mode */
+		mdelay(1000);
+		if (!(retval < CY_OK)) {
+			retval = i2c_smbus_read_i2c_block_data(ts->client,
+				CY_REG_BASE,
+				sizeof(struct cyttsp_sysinfo_data_t),
+				(u8 *)&g_sysinfo_data);
+			cyttsp_debug("SI2: hst_mode=0x%02X mfg_cmd=0x%02X mfg_stat=0x%02X\n", \
+				g_sysinfo_data.hst_mode, \
+				g_sysinfo_data.mfg_cmd, \
+				g_sysinfo_data.mfg_stat);
+			cyttsp_debug("SI2: bl_ver=0x%02X%02X\n", \
+				g_sysinfo_data.bl_verh, \
+				g_sysinfo_data.bl_verl);
+			cyttsp_debug("SI2: sysinfo act_int=0x%02X tch_tmout=0x%02X lp_int=0x%02X\n", \
+				g_sysinfo_data.act_intrvl, \
+				g_sysinfo_data.tch_tmout, \
+				g_sysinfo_data.lp_intrvl);
+			cyttsp_info("SI%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
+				102, \
+				g_sysinfo_data.tts_verh, \
+				g_sysinfo_data.tts_verl, \
+				g_sysinfo_data.app_idh, \
+				g_sysinfo_data.app_idl, \
+				g_sysinfo_data.app_verh, \
+				g_sysinfo_data.app_verl);
+			cyttsp_info("SI%d: c_id=%02X%02X%02X\n", \
+				103, \
+				g_sysinfo_data.cid[0], \
+				g_sysinfo_data.cid[1], \
+				g_sysinfo_data.cid[2]);
+			if (!(retval < CY_OK) &&
+				(CY_DIFF(ts->platform_data->act_intrvl,
+					CY_ACT_INTRVL_DFLT)  ||
+				CY_DIFF(ts->platform_data->tch_tmout,
+					CY_TCH_TMOUT_DFLT) ||
+				CY_DIFF(ts->platform_data->lp_intrvl,
+					CY_LP_INTRVL_DFLT))) {
+				if (!(retval < CY_OK)) {
+					u8 intrvl_ray[sizeof(ts->platform_data->act_intrvl) +
+						sizeof(ts->platform_data->tch_tmout) +
+						sizeof(ts->platform_data->lp_intrvl)];
+					u8 i = 0;
+
+					intrvl_ray[i++] =
+						ts->platform_data->act_intrvl;
+					intrvl_ray[i++] =
+						ts->platform_data->tch_tmout;
+					intrvl_ray[i++] =
+						ts->platform_data->lp_intrvl;
+
+					cyttsp_debug("SI2: platinfo act_intrvl=0x%02X tch_tmout=0x%02X lp_intrvl=0x%02X\n", \
+						ts->platform_data->act_intrvl, \
+						ts->platform_data->tch_tmout, \
+						ts->platform_data->lp_intrvl);
+					/* set intrvl registers */
+					retval = i2c_smbus_write_i2c_block_data(
+						ts->client,
+						CY_REG_ACT_INTRVL,
+						sizeof(intrvl_ray), intrvl_ray);
+					mdelay(CY_DLY_SYSINFO);
+				}
+			}
+		}
+		/* switch back to Operational mode */
+		cyttsp_debug("switch back to operational mode \n");
+		if (!(retval < CY_OK)) {
+			host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
+			retval = i2c_smbus_write_i2c_block_data(ts->client,
+				CY_REG_BASE,
+				sizeof(host_reg), &host_reg);
+			/* wait for TTSP Device to complete
+			 * switch to Operational mode */
+			mdelay(1000);
+		}
+	}
+	/* init gesture setup;
+	 * this is required even if not using gestures
+	 * in order to set the active distance */
+	if (!(retval < CY_OK)) {
+		u8 gesture_setup;
+		cyttsp_debug("init gesture setup \n");
+		gesture_setup = ts->platform_data->gest_set;
+		retval = i2c_smbus_write_i2c_block_data(ts->client,
+			CY_REG_GEST_SET,
+			sizeof(gesture_setup), &gesture_setup);
+		mdelay(CY_DLY_DFLT);
+	}
+
+	if (!(retval < CY_OK))
+		ts->platform_data->power_state = CY_ACTIVE_STATE;
+	else
+		ts->platform_data->power_state = CY_IDLE_STATE;
+
+	cyttsp_debug("Retval=%d Power state is %s\n", \
+		retval, \
+		ts->platform_data->power_state == CY_ACTIVE_STATE ? \
+		 "ACTIVE" : "IDLE");
+
+	return retval;
+}
+
+/* cyttsp_initialize: Driver Initialization. This function takes
+ * care of the following tasks:
+ * 1. Create and register an input device with input layer
+ * 2. Take CYTTSP device out of bootloader mode; go operational
+ * 3. Start any timers/Work queues.  */
+static int cyttsp_initialize(struct i2c_client *client, struct cyttsp *ts)
+{
+	struct input_dev *input_device;
+	int error = 0;
+	int retval = CY_OK;
+	u8 id;
+
+	/* Create the input device and register it. */
+	input_device = input_allocate_device();
+	if (!input_device) {
+		error = -ENOMEM;
+		cyttsp_xdebug1("err input allocate device\n");
+		goto error_free_device;
+	}
+
+	if (!client) {
+		error = ~ENODEV;
+		cyttsp_xdebug1("err client is Null\n");
+		goto error_free_device;
+	}
+
+	if (!ts) {
+		error = ~ENODEV;
+		cyttsp_xdebug1("err context is Null\n");
+		goto error_free_device;
+	}
+
+	ts->input = input_device;
+	input_device->name = CY_I2C_NAME;
+	input_device->phys = ts->phys;
+	input_device->dev.parent = &client->dev;
+
+	/* init the touch structures */
+	ts->num_prv_st_tch = CY_NTCH;
+	for (id = 0; id < CY_NUM_TRK_ID; id++) {
+		ts->act_trk[id] = CY_NTCH;
+		ts->prv_mt_pos[id][CY_XPOS] = 0;
+		ts->prv_mt_pos[id][CY_YPOS] = 0;
+	}
+
+	for (id = 0; id < CY_NUM_MT_TCH_ID; id++)
+		ts->prv_mt_tch[id] = CY_IGNR_TCH;
+
+	for (id = 0; id < CY_NUM_ST_TCH_ID; id++)
+		ts->prv_st_tch[id] = CY_IGNR_TCH;
+
+	set_bit(EV_SYN, input_device->evbit);
+	set_bit(EV_KEY, input_device->evbit);
+	set_bit(EV_ABS, input_device->evbit);
+	set_bit(BTN_TOUCH, input_device->keybit);
+	set_bit(BTN_2, input_device->keybit);
+	if (ts->platform_data->use_gestures)
+		set_bit(BTN_3, input_device->keybit);
+
+	input_set_abs_params(input_device,
+		ABS_X, 0, ts->platform_data->maxx, 0, 0);
+	input_set_abs_params(input_device,
+		ABS_Y, 0, ts->platform_data->maxy, 0, 0);
+	input_set_abs_params(input_device,
+		ABS_TOOL_WIDTH, 0, CY_LARGE_TOOL_WIDTH, 0 , 0);
+	input_set_abs_params(input_device,
+		ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
+	input_set_abs_params(input_device,
+		ABS_HAT0X, 0, ts->platform_data->maxx, 0, 0);
+	input_set_abs_params(input_device,
+		ABS_HAT0Y, 0, ts->platform_data->maxy, 0, 0);
+	if (ts->platform_data->use_gestures) {
+		input_set_abs_params(input_device,
+			ABS_HAT1X, 0, CY_MAXZ, 0, 0);
+		input_set_abs_params(input_device,
+			ABS_HAT1Y, 0, CY_MAXZ, 0, 0);
+	}
+	if (ts->platform_data->use_mt) {
+		input_set_abs_params(input_device,
+			ABS_MT_POSITION_X, 0, ts->platform_data->maxx, 0, 0);
+		input_set_abs_params(input_device,
+			ABS_MT_POSITION_Y, 0, ts->platform_data->maxy, 0, 0);
+		input_set_abs_params(input_device,
+			ABS_MT_TOUCH_MAJOR, 0, CY_MAXZ, 0, 0);
+		input_set_abs_params(input_device,
+			ABS_MT_WIDTH_MAJOR, 0, CY_LARGE_TOOL_WIDTH, 0, 0);
+		if (ts->platform_data->use_trk_id) {
+			input_set_abs_params(input_device,
+				ABS_MT_TRACKING_ID, 0, CY_NUM_TRK_ID, 0, 0);
+		}
+	}
+
+	/* set dummy key to make driver work with virtual keys */
+	input_set_capability(input_device, EV_KEY, KEY_PROG1);
+
+	cyttsp_info("%s: Register input device\n", CY_I2C_NAME);
+	error = input_register_device(input_device);
+	if (error) {
+		cyttsp_alert("%s: Failed to register input device\n", \
+			CY_I2C_NAME);
+		retval = error;
+		goto error_free_device;
+	}
+
+	/* Prepare our worker structure prior to setting up the timer/ISR */
+	INIT_WORK(&ts->work, cyttsp_xy_worker);
+
+	/* Power on the chip and make sure that I/Os are set as specified
+	 * in the platform */
+	if (ts->platform_data->init)
+		retval = ts->platform_data->init(client);
+
+	if (!(retval < CY_OK))
+		retval = cyttsp_power_on(ts);
+
+	if (retval < 0)
+		goto error_free_device;
+
+	/* Timer or Interrupt setup */
+	if (ts->client->irq == 0) {
+		cyttsp_info("Setting up timer\n");
+		setup_timer(&ts->timer, cyttsp_timer, (unsigned long) ts);
+		mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
+	} else {
+		cyttsp_info("Setting up interrupt\n");
+		/* request_irq() will also call enable_irq() */
+		error = request_irq(client->irq, cyttsp_irq,
+			IRQF_TRIGGER_FALLING,
+			client->dev.driver->name, ts);
+		if (error) {
+			cyttsp_alert("error: could not request irq\n");
+			retval = error;
+			goto error_free_irq;
+		}
+	}
+
+	irq_cnt = 0;
+	irq_cnt_total = 0;
+	irq_err_cnt = 0;
+
+	atomic_set(&ts->irq_enabled, 1);
+	retval = device_create_file(&ts->client->dev, &dev_attr_irq_enable);
+	if (retval < CY_OK) {
+		cyttsp_alert("File device creation failed: %d\n", retval);
+		retval = -ENODEV;
+		goto error_free_irq;
+	}
+
+	cyttsp_info("%s: Successful registration\n", CY_I2C_NAME);
+	goto success;
+
+error_free_irq:
+	cyttsp_alert("Error: Failed to register IRQ handler\n");
+	free_irq(client->irq, ts);
+
+error_free_device:
+	if (input_device)
+		input_free_device(input_device);
+
+success:
+	return retval;
+}
+
+/* I2C driver probe function */
+static int __devinit cyttsp_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct cyttsp *ts;
+	int error;
+	int retval = CY_OK;
+
+	cyttsp_info("Start Probe 1.2\n");
+
+	/* allocate and clear memory */
+	ts = kzalloc(sizeof(struct cyttsp), GFP_KERNEL);
+	if (ts == NULL) {
+		cyttsp_xdebug1("err kzalloc for cyttsp\n");
+		retval = -ENOMEM;
+	}
+
+	if (!(retval < CY_OK)) {
+		/* register driver_data */
+		ts->client = client;
+		ts->platform_data = client->dev.platform_data;
+		i2c_set_clientdata(client, ts);
+
+		error = cyttsp_initialize(client, ts);
+		if (error) {
+			cyttsp_xdebug1("err cyttsp_initialize\n");
+			if (ts != NULL) {
+				/* deallocate memory */
+				kfree(ts);
+			}
+/*
+			i2c_del_driver(&cyttsp_driver);
+*/
+			retval = -ENODEV;
+		} else
+			cyttsp_openlog();
+	}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	if (!(retval < CY_OK)) {
+		ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+		ts->early_suspend.suspend = cyttsp_early_suspend;
+		ts->early_suspend.resume = cyttsp_late_resume;
+		register_early_suspend(&ts->early_suspend);
+	}
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+	cyttsp_info("Start Probe %s\n", \
+		(retval < CY_OK) ? "FAIL" : "PASS");
+
+	return retval;
+}
+
+/* Function to manage power-on resume */
+static int cyttsp_resume(struct i2c_client *client)
+{
+	struct cyttsp *ts;
+	int retval = CY_OK;
+
+	cyttsp_debug("Wake Up\n");
+	ts = (struct cyttsp *) i2c_get_clientdata(client);
+
+	/* re-enable the interrupt prior to wake device */
+	if (ts->client->irq)
+		enable_irq(ts->client->irq);
+
+	if (ts->platform_data->use_sleep &&
+		(ts->platform_data->power_state != CY_ACTIVE_STATE)) {
+		if (ts->platform_data->resume)
+			retval = ts->platform_data->resume(client);
+		if (!(retval < CY_OK)) {
+			retval = i2c_smbus_read_i2c_block_data(ts->client,
+				CY_REG_BASE,
+				sizeof(struct cyttsp_bootloader_data_t),
+				(u8 *)&g_bl_data);
+			if (!(retval < CY_OK) &&
+				GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
+				u8 tries;
+				retval = i2c_smbus_write_i2c_block_data(
+					ts->client,
+					CY_REG_BASE,
+					sizeof(bl_cmd), bl_cmd);
+				/* switch back to operational mode */
+				tries = 0;
+				mdelay(10);
+				while (GET_BOOTLOADERMODE(g_bl_data.bl_status)
+					&& tries++ < 10) {
+					mdelay(100);
+					cyttsp_putbl(ts, 16,
+						false, false, false);
+				}
+			}
+		}
+	}
+
+	if (!(retval < CY_OK) &&
+		(GET_HSTMODE(g_bl_data.bl_file) == CY_OK)) {
+		ts->platform_data->power_state = CY_ACTIVE_STATE;
+
+		/* re-enable the timer after resuming */
+		if (ts->client->irq == 0)
+			mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
+	} else
+		retval = -ENODEV;
+
+	cyttsp_debug("Wake Up %s\n", \
+		(retval < CY_OK) ? "FAIL" : "PASS");
+
+	return retval;
+}
+
+
+/* Function to manage low power suspend */
+static int cyttsp_suspend(struct i2c_client *client, pm_message_t message)
+{
+	struct cyttsp *ts;
+	u8 sleep_mode = CY_OK;
+	int retval = CY_OK;
+
+	cyttsp_debug("Enter Sleep\n");
+	ts = (struct cyttsp *) i2c_get_clientdata(client);
+
+	/* disable worker */
+	if (ts->client->irq == 0)
+		del_timer(&ts->timer);
+	else
+		disable_irq_nosync(ts->client->irq);
+	retval = cancel_work_sync(&ts->work);
+
+	if (retval)
+		enable_irq(ts->client->irq);
+
+	if (!(retval < CY_OK)) {
+		if (ts->platform_data->use_sleep &&
+			(ts->platform_data->power_state == CY_ACTIVE_STATE)) {
+			if (ts->platform_data->use_sleep & CY_USE_DEEP_SLEEP_SEL)
+				sleep_mode = CY_DEEP_SLEEP_MODE;
+			else
+				sleep_mode = CY_LOW_PWR_MODE;
+
+			retval = i2c_smbus_write_i2c_block_data(ts->client,
+				CY_REG_BASE,
+				sizeof(sleep_mode), &sleep_mode);
+		}
+	}
+
+	if (!(retval < CY_OK)) {
+		if (sleep_mode == CY_DEEP_SLEEP_MODE)
+			ts->platform_data->power_state = CY_SLEEP_STATE;
+		else if (sleep_mode == CY_LOW_PWR_MODE)
+			ts->platform_data->power_state = CY_LOW_PWR_STATE;
+	}
+
+	cyttsp_debug("Sleep Power state is %s\n", \
+		(ts->platform_data->power_state == CY_ACTIVE_STATE) ? \
+		"ACTIVE" : \
+		((ts->platform_data->power_state == CY_SLEEP_STATE) ? \
+		"SLEEP" : "LOW POWER"));
+
+	return retval;
+}
+
+/* registered in driver struct */
+static int __devexit cyttsp_remove(struct i2c_client *client)
+{
+	struct cyttsp *ts;
+	int err;
+
+	cyttsp_alert("Unregister\n");
+
+	/* clientdata registered on probe */
+	ts = i2c_get_clientdata(client);
+	device_remove_file(&ts->client->dev, &dev_attr_irq_enable);
+
+	/* Start cleaning up by removing any delayed work and the timer */
+	if (cancel_delayed_work((struct delayed_work *)&ts->work) < CY_OK)
+		cyttsp_alert("error: could not remove work from workqueue\n");
+
+	/* free up timer or irq */
+	if (ts->client->irq == 0) {
+		err = del_timer(&ts->timer);
+		if (err < CY_OK)
+			cyttsp_alert("error: failed to delete timer\n");
+	} else
+		free_irq(client->irq, ts);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&ts->early_suspend);
+#endif /* CONFIG_HAS_EARLYSUSPEND */
+
+	/* housekeeping */
+	if (ts != NULL)
+		kfree(ts);
+
+	cyttsp_alert("Leaving\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void cyttsp_early_suspend(struct early_suspend *handler)
+{
+	struct cyttsp *ts;
+
+	ts = container_of(handler, struct cyttsp, early_suspend);
+	cyttsp_suspend(ts->client, PMSG_SUSPEND);
+}
+
+static void cyttsp_late_resume(struct early_suspend *handler)
+{
+	struct cyttsp *ts;
+
+	ts = container_of(handler, struct cyttsp, early_suspend);
+	cyttsp_resume(ts->client);
+}
+#endif  /* CONFIG_HAS_EARLYSUSPEND */
+
+static int cyttsp_init(void)
+{
+	int ret;
+
+	cyttsp_info("Cypress TrueTouch(R) Standard Product\n");
+	cyttsp_info("I2C Touchscreen Driver (Built %s @ %s)\n", \
+		__DATE__, __TIME__);
+
+	cyttsp_ts_wq = create_singlethread_workqueue("cyttsp_ts_wq");
+	if (cyttsp_ts_wq == NULL) {
+		cyttsp_debug("No memory for cyttsp_ts_wq\n");
+		return -ENOMEM;
+	}
+
+	ret = i2c_add_driver(&cyttsp_driver);
+
+	return ret;
+}
+
+static void cyttsp_exit(void)
+{
+	if (cyttsp_ts_wq)
+		destroy_workqueue(cyttsp_ts_wq);
+	return i2c_del_driver(&cyttsp_driver);
+}
+
+module_init(cyttsp_init);
+module_exit(cyttsp_exit);
+
diff --git a/include/linux/cyttsp.h b/include/linux/cyttsp.h
new file mode 100644
index 0000000..2ab1a5c
--- /dev/null
+++ b/include/linux/cyttsp.h
@@ -0,0 +1,649 @@
+/* Header file for:
+ * Cypress TrueTouch(TM) Standard Product touchscreen drivers.
+ * include/linux/cyttsp.h
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Cypress reserves the right to make changes without further notice
+ * to the materials described herein. Cypress does not assume any
+ * liability arising out of the application described herein.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com
+ *
+ */
+
+
+#ifndef __CYTTSP_H__
+#define __CYTTSP_H__
+
+#include <linux/input.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#define CYPRESS_TTSP_NAME	"cyttsp"
+#define CY_I2C_NAME		"cyttsp-i2c"
+#define CY_SPI_NAME		"cyttsp-spi"
+
+#ifdef CY_DECLARE_GLOBALS
+	uint32_t cyttsp_tsdebug;
+	module_param_named(tsdebug, cyttsp_tsdebug, uint, 0664);
+	uint32_t cyttsp_tsxdebug;
+	module_param_named(tsxdebug, cyttsp_tsxdebug, uint, 0664);
+
+	uint32_t cyttsp_disable_touch;
+	module_param_named(disable_touch, cyttsp_disable_touch, uint, 0664);
+#else
+	extern uint32_t cyttsp_tsdebug;
+	extern uint32_t cyttsp_tsxdebug;
+	extern uint32_t cyttsp_disable_touch;
+#endif
+
+
+
+/******************************************************************************
+ * Global Control, Used to control the behavior of the driver
+ */
+
+/* defines for Gen2 (Txx2xx); Gen3 (Txx3xx)
+ * use these defines to set cyttsp_platform_data.gen in board config file
+ */
+#define CY_GEN2		2
+#define CY_GEN3		3
+
+/* define for using I2C driver
+ */
+#define CY_USE_I2C_DRIVER
+
+/* defines for using SPI driver */
+/*
+#define CY_USE_SPI_DRIVER
+ */
+#define CY_SPI_DFLT_SPEED_HZ		1000000
+#define CY_SPI_MAX_SPEED_HZ		4000000
+#define CY_SPI_SPEED_HZ			CY_SPI_DFLT_SPEED_HZ
+#define CY_SPI_BITS_PER_WORD		8
+#define CY_SPI_DAV			139	/* set correct gpio id */
+#define CY_SPI_BUFSIZE			512
+
+
+/* define for inclusion of TTSP App Update Load File
+ * use this define if update to the TTSP Device is desired
+ */
+/*
+#define CY_INCLUDE_LOAD_FILE
+*/
+
+/* define if force new load file for bootloader load */
+/*
+#define CY_FORCE_FW_UPDATE
+*/
+
+/* undef for production use */
+/*
+ */
+#define CY_USE_DEBUG
+
+/* undef for irq use; use this define in the board configuration file */
+/*
+#define CY_USE_TIMER
+ */
+
+/* undef to allow use of extra debug capability */
+/*
+#define CY_ALLOW_EXTRA_DEBUG
+*/
+
+/* undef to remove additional debug prints */
+/*
+#define CY_USE_EXTRA_DEBUG
+*/
+
+/* undef to remove additional debug prints */
+/*
+#define CY_USE_EXTRA_DEBUG1
+ */
+
+/* undef to use operational touch timer jiffies; else use test jiffies */
+/*
+#define CY_USE_TIMER_DEBUG
+ */
+
+/* define to use canned test data */
+/*
+#define CY_USE_TEST_DATA
+ */
+
+/* define to activate power management */
+/*
+#define CY_USE_LOW_POWER
+ */
+
+/* define if wake on i2c addr is activated */
+/*
+#define CY_USE_DEEP_SLEEP
+ */
+
+/* define if gesture signaling is used
+ * and which gesture groups to use
+ */
+/*
+#define CY_USE_GEST
+#define CY_USE_GEST_GRP1
+#define CY_USE_GEST_GRP2
+#define CY_USE_GEST_GRP3
+#define CY_USE_GEST_GRP4
+ */
+/* Active distance in pixels for a gesture to be reported
+ * if set to 0, then all gesture movements are reported
+ */
+#define CY_ACT_DIST_DFLT	8
+#define CY_ACT_DIST			CY_ACT_DIST_DFLT
+
+/* define if MT signals are desired */
+/*
+*/
+#define CY_USE_MT_SIGNALS
+
+/* define if MT tracking id signals are used */
+/*
+#define CY_USE_MT_TRACK_ID
+ */
+
+/* define if ST signals are required */
+/*
+#define CY_USE_ST_SIGNALS
+*/
+
+/* define to send handshake to device */
+/*
+#define CY_USE_HNDSHK
+*/
+
+/* define if log all raw motion signals to a sysfs file */
+/*
+#define CY_LOG_TO_FILE
+*/
+
+
+/* End of the Global Control section
+ ******************************************************************************
+ */
+#define CY_DIFF(m, n)		((m) != (n))
+
+#ifdef CY_LOG_TO_FILE
+	#define cyttsp_openlog()	/* use sysfs */
+#else
+	#define cyttsp_openlog()
+#endif /* CY_LOG_TO_FILE */
+
+/* see kernel.h for pr_xxx def'ns */
+#define cyttsp_info(f, a...)		pr_info("%s:" f,  __func__ , ## a)
+#define cyttsp_error(f, a...)		pr_err("%s:" f,  __func__ , ## a)
+#define cyttsp_alert(f, a...)		pr_alert("%s:" f,  __func__ , ## a)
+
+#ifdef CY_USE_DEBUG
+	#define cyttsp_debug(f, a...)	pr_alert("%s:" f,  __func__ , ## a)
+#else
+	#define cyttsp_debug(f, a...)	{if (cyttsp_tsdebug) \
+					pr_alert("%s:" f,  __func__ , ## a); }
+#endif /* CY_USE_DEBUG */
+
+#ifdef CY_ALLOW_EXTRA_DEBUG
+#ifdef CY_USE_EXTRA_DEBUG
+	#define cyttsp_xdebug(f, a...)	pr_alert("%s:" f,  __func__ , ## a)
+#else
+	#define cyttsp_xdebug(f, a...)	{if (cyttsp_tsxdebug) \
+					pr_alert("%s:" f,  __func__ , ## a); }
+#endif /* CY_USE_EXTRA_DEBUG */
+
+#ifdef CY_USE_EXTRA_DEBUG1
+	#define cyttsp_xdebug1(f, a...)	pr_alert("%s:" f,  __func__ , ## a)
+#else
+	#define cyttsp_xdebug1(f, a...)
+#endif /* CY_USE_EXTRA_DEBUG1 */
+#else
+	#define cyttsp_xdebug(f, a...)
+	#define cyttsp_xdebug1(f, a...)
+#endif /* CY_ALLOW_EXTRA_DEBUG */
+
+#ifdef CY_USE_TIMER_DEBUG
+	#define	TOUCHSCREEN_TIMEOUT	(msecs_to_jiffies(1000))
+#else
+	#define	TOUCHSCREEN_TIMEOUT	(msecs_to_jiffies(28))
+#endif
+
+/* reduce extra signals in MT only build
+ * be careful not to lose backward compatibility for pre-MT apps
+ */
+#ifdef CY_USE_ST_SIGNALS
+	#define CY_USE_ST	1
+#else
+	#define CY_USE_ST	0
+#endif /* CY_USE_ST_SIGNALS */
+
+/* rely on kernel input.h to define Multi-Touch capability */
+/* if input.h defines the Multi-Touch signals, then use MT */
+#if defined(ABS_MT_TOUCH_MAJOR) && defined(CY_USE_MT_SIGNALS)
+	#define CY_USE_MT	1
+	#define CY_MT_SYNC(input)	input_mt_sync(input)
+#else
+	#define CY_USE_MT	0
+	#define CY_MT_SYNC(input)
+	/* the following includes are provided to ensure a compile;
+	 * the code that compiles with these defines will not be executed if
+	 * the CY_USE_MT is properly used in the platform structure init
+	 */
+	#ifndef ABS_MT_TOUCH_MAJOR
+	#define ABS_MT_TOUCH_MAJOR	0x30	/* touching ellipse */
+	#define ABS_MT_TOUCH_MINOR	0x31	/* (omit if circular) */
+	#define ABS_MT_WIDTH_MAJOR	0x32	/* approaching ellipse */
+	#define ABS_MT_WIDTH_MINOR	0x33	/* (omit if circular) */
+	#define ABS_MT_ORIENTATION	0x34	/* Ellipse orientation */
+	#define ABS_MT_POSITION_X	0x35	/* Center X ellipse position */
+	#define ABS_MT_POSITION_Y	0x36	/* Center Y ellipse position */
+	#define ABS_MT_TOOL_TYPE	0x37	/* Type of touching device */
+	#define ABS_MT_BLOB_ID		0x38	/* Group set of pkts as blob */
+	#endif /* ABS_MT_TOUCH_MAJOR */
+#endif /* ABS_MT_TOUCH_MAJOR and CY_USE_MT_SIGNALS */
+#if defined(ABS_MT_TRACKING_ID)  && defined(CY_USE_MT_TRACK_ID)
+	#define CY_USE_TRACKING_ID	1
+#else
+	#define CY_USE_TRACKING_ID	0
+/* define only if not defined already by system;
+ * value based on linux kernel 2.6.30.10
+ */
+#ifndef ABS_MT_TRACKING_ID
+	#define ABS_MT_TRACKING_ID	(ABS_MT_BLOB_ID+1)
+#endif
+#endif /* ABS_MT_TRACKING_ID */
+
+#ifdef CY_USE_DEEP_SLEEP
+	#define CY_USE_DEEP_SLEEP_SEL	0x80
+#else
+	#define CY_USE_DEEP_SLEEP_SEL	0x00
+#endif
+#ifdef CY_USE_LOW_POWER
+	#define CY_USE_SLEEP	(CY_USE_DEEP_SLEEP_SEL | 0x01)
+#else
+	#define CY_USE_SLEEP	0x00
+#endif /* CY_USE_LOW_POWER */
+
+#ifdef CY_USE_TEST_DATA
+	#define cyttsp_testdat(ray1, ray2, sizeofray) \
+		{ \
+			int i; \
+			u8 *up1 = (u8 *)ray1; \
+			u8 *up2 = (u8 *)ray2; \
+			for (i = 0; i < sizeofray; i++) { \
+				up1[i] = up2[i]; \
+			} \
+		}
+#else
+	#define cyttsp_testdat(xy, test_xy, sizeofray)
+#endif /* CY_USE_TEST_DATA */
+
+/* helper macros */
+#define GET_NUM_TOUCHES(x)		((x) & 0x0F)
+#define GET_TOUCH1_ID(x)		(((x) & 0xF0) >> 4)
+#define GET_TOUCH2_ID(x)		((x) & 0x0F)
+#define GET_TOUCH3_ID(x)		(((x) & 0xF0) >> 4)
+#define GET_TOUCH4_ID(x)		((x) & 0x0F)
+#define IS_LARGE_AREA(x)		(((x) & 0x10) >> 4)
+#define FLIP_DATA_FLAG			0x01
+#define REVERSE_X_FLAG			0x02
+#define REVERSE_Y_FLAG			0x04
+#define FLIP_DATA(flags)		((flags) & FLIP_DATA_FLAG)
+#define REVERSE_X(flags)		((flags) & REVERSE_X_FLAG)
+#define REVERSE_Y(flags)		((flags) & REVERSE_Y_FLAG)
+#define FLIP_XY(x, y)			{ \
+						u16 tmp; \
+						tmp = (x); \
+						(x) = (y); \
+						(y) = tmp; \
+					}
+#define INVERT_X(x, xmax)		((xmax) - (x))
+#define INVERT_Y(y, ymax)		((ymax) - (y))
+#define SET_HSTMODE(reg, mode)		((reg) & (mode))
+#define GET_HSTMODE(reg)		((reg & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)		((reg & 0x10) >> 4)
+
+/* constant definitions */
+/* maximum number of concurrent ST track IDs */
+#define CY_NUM_ST_TCH_ID		2
+
+/* maximum number of concurrent MT track IDs */
+#define CY_NUM_MT_TCH_ID		4
+
+/* maximum number of track IDs */
+#define CY_NUM_TRK_ID			16
+
+#define CY_NTCH				0	/* no touch (lift off) */
+#define CY_TCH				1	/* active touch (touchdown) */
+#define CY_ST_FNGR1_IDX			0
+#define CY_ST_FNGR2_IDX			1
+#define CY_MT_TCH1_IDX			0
+#define CY_MT_TCH2_IDX			1
+#define CY_MT_TCH3_IDX			2
+#define CY_MT_TCH4_IDX			3
+#define CY_XPOS				0
+#define CY_YPOS				1
+#define CY_IGNR_TCH			(-1)
+#define CY_SMALL_TOOL_WIDTH		10
+#define CY_LARGE_TOOL_WIDTH		255
+#define CY_REG_BASE			0x00
+#define CY_REG_GEST_SET			0x1E
+#define CY_REG_ACT_INTRVL		0x1D
+#define CY_REG_TCH_TMOUT		(CY_REG_ACT_INTRVL+1)
+#define CY_REG_LP_INTRVL		(CY_REG_TCH_TMOUT+1)
+#define CY_SOFT_RESET			((1 << 0))
+#define CY_DEEP_SLEEP			((1 << 1))
+#define CY_LOW_POWER			((1 << 2))
+#define CY_MAXZ				255
+#define CY_OK				0
+#define CY_INIT				1
+#define	CY_DLY_DFLT			10	/* ms */
+#define CY_DLY_SYSINFO			20	/* ms */
+#define CY_DLY_BL			300
+#define CY_DLY_DNLOAD			100	/* ms */
+#define CY_NUM_RETRY			4	/* max num touch data read */
+
+/* handshake bit in the hst_mode reg */
+#define CY_HNDSHK_BIT			0x80
+#ifdef CY_USE_HNDSHK
+	#define CY_SEND_HNDSHK		1
+#else
+	#define CY_SEND_HNDSHK		0
+#endif
+
+/* Bootloader File 0 offset */
+#define CY_BL_FILE0			0x00
+
+/* Bootloader command directive */
+#define CY_BL_CMD			0xFF
+
+/* Bootloader Initiate Bootload */
+#define CY_BL_INIT_LOAD			0x38
+
+/* Bootloader Write a Block */
+#define CY_BL_WRITE_BLK			0x39
+
+/* Bootloader Terminate Bootload */
+#define CY_BL_TERMINATE			0x3B
+
+/* Bootloader Exit and Verify Checksum command */
+#define CY_BL_EXIT			0xA5
+
+/* Bootloader default keys */
+#define CY_BL_KEY0			0x00
+#define CY_BL_KEY1			0x01
+#define CY_BL_KEY2			0x02
+#define CY_BL_KEY3			0x03
+#define CY_BL_KEY4			0x04
+#define CY_BL_KEY5			0x05
+#define CY_BL_KEY6			0x06
+#define CY_BL_KEY7			0x07
+
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT		0x00
+
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT		0xFF
+
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT		0x0A
+
+#define CY_IDLE_STATE		0
+#define CY_ACTIVE_STATE		1
+#define CY_LOW_PWR_STATE		2
+#define CY_SLEEP_STATE		3
+
+/* device mode bits */
+#define CY_OP_MODE		0x00
+#define CY_SYSINFO_MODE		0x10
+
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE		0x01	/* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE		0x02
+#define CY_LOW_PWR_MODE		0x04
+
+#define CY_NUM_KEY			8
+
+#ifdef CY_USE_GEST
+	#define CY_USE_GESTURES	1
+#else
+	#define CY_USE_GESTURES	0
+#endif /* CY_USE_GESTURE_SIGNALS */
+
+#ifdef CY_USE_GEST_GRP1
+	#define CY_GEST_GRP1	0x10
+#else
+	#define CY_GEST_GRP1	0x00
+#endif	/* CY_USE_GEST_GRP1 */
+#ifdef CY_USE_GEST_GRP2
+	#define CY_GEST_GRP2	0x20
+#else
+	#define CY_GEST_GRP2	0x00
+#endif	/* CY_USE_GEST_GRP2 */
+#ifdef CY_USE_GEST_GRP3
+	#define CY_GEST_GRP3	0x40
+#else
+	#define CY_GEST_GRP3	0x00
+#endif	/* CY_USE_GEST_GRP3 */
+#ifdef CY_USE_GEST_GRP4
+	#define CY_GEST_GRP4	0x80
+#else
+	#define CY_GEST_GRP4	0x00
+#endif	/* CY_USE_GEST_GRP4 */
+
+
+struct cyttsp_platform_data {
+	u32 maxx;
+	u32 maxy;
+	u32 flags;
+	u8 gen;
+	u8 use_st;
+	u8 use_mt;
+	u8 use_hndshk;
+	u8 use_trk_id;
+	u8 use_sleep;
+	u8 use_gestures;
+	u8 gest_set;
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+	u8 power_state;
+#ifdef CY_USE_I2C_DRIVER
+	s32 (*init)(struct i2c_client *client);
+	s32 (*resume)(struct i2c_client *client);
+#endif
+#ifdef CY_USE_SPI_DRIVER
+	s32 (*init)(struct spi_device *spi);
+	s32 (*resume)(struct spi_device *spi);
+#endif
+};
+
+/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */
+struct cyttsp_gen3_xydata_t {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	u16 x1 __attribute__ ((packed));
+	u16 y1 __attribute__ ((packed));
+	u8 z1;
+	u8 touch12_id;
+	u16 x2 __attribute__ ((packed));
+	u16 y2 __attribute__ ((packed));
+	u8 z2;
+	u8 gest_cnt;
+	u8 gest_id;
+	u16 x3 __attribute__ ((packed));
+	u16 y3 __attribute__ ((packed));
+	u8 z3;
+	u8 touch34_id;
+	u16 x4 __attribute__ ((packed));
+	u16 y4 __attribute__ ((packed));
+	u8 z4;
+	u8 tt_undef[3];
+	u8 gest_set;
+	u8 tt_reserved;
+};
+
+/* TrueTouch Standard Product Gen2 (Txx2xx) interface definition */
+#define CY_GEN2_NOTOUCH		0x03	/* Both touches removed */
+#define CY_GEN2_GHOST		0x02	/* ghost */
+#define CY_GEN2_2TOUCH		0x03	/* 2 touch; no ghost */
+#define CY_GEN2_1TOUCH		0x01	/* 1 touch only */
+#define CY_GEN2_TOUCH2		0x01	/* 1st touch removed;
+						 * 2nd touch remains */
+struct cyttsp_gen2_xydata_t {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	u16 x1 __attribute__ ((packed));
+	u16 y1 __attribute__ ((packed));
+	u8 z1;
+	u8 evnt_idx;
+	u16 x2 __attribute__ ((packed));
+	u16 y2 __attribute__ ((packed));
+	u8 tt_undef1;
+	u8 gest_cnt;
+	u8 gest_id;
+	u8 tt_undef[14];
+	u8 gest_set;
+	u8 tt_reserved;
+};
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data_t {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[6];
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK		0x01
+struct cyttsp_bootloader_data_t {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+#define cyttsp_wake_data_t		cyttsp_gen3_xydata_t
+#ifdef CY_DECLARE_GLOBALS
+	#ifdef CY_INCLUDE_LOAD_FILE
+		/* this file declares:
+		 * firmware download block array (cyttsp_fw[]),
+		 * the number of command block records (cyttsp_fw_records),
+		 * and the version variables
+		 */
+		#include "cyttsp_fw.h"		/* imports cyttsp_fw[] array */
+		#define cyttsp_app_load()	1
+		#ifdef CY_FORCE_FW_UPDATE
+			#define cyttsp_force_fw_load()	1
+		#else
+			#define cyttsp_force_fw_load()	0
+		#endif
+
+	#else
+		/* the following declarations are to allow
+		 * some debugging capability
+		 */
+		unsigned char cyttsp_fw_tts_verh = 0x00;
+		unsigned char cyttsp_fw_tts_verl = 0x01;
+		unsigned char cyttsp_fw_app_idh = 0x02;
+		unsigned char cyttsp_fw_app_idl = 0x03;
+		unsigned char cyttsp_fw_app_verh = 0x04;
+		unsigned char cyttsp_fw_app_verl = 0x05;
+		unsigned char cyttsp_fw_cid_0 = 0x06;
+		unsigned char cyttsp_fw_cid_1 = 0x07;
+		unsigned char cyttsp_fw_cid_2 = 0x08;
+		#define cyttsp_app_load()	0
+		#define cyttsp_force_fw_load()	0
+	#endif
+	#define cyttsp_tts_verh()	cyttsp_fw_tts_verh
+	#define cyttsp_tts_verl()	cyttsp_fw_tts_verl
+	#define cyttsp_app_idh()	cyttsp_fw_app_idh
+	#define cyttsp_app_idl()	cyttsp_fw_app_idl
+	#define cyttsp_app_verh()	cyttsp_fw_app_verh
+	#define cyttsp_app_verl()	cyttsp_fw_app_verl
+	#define cyttsp_cid_0()		cyttsp_fw_cid_0
+	#define cyttsp_cid_1()		cyttsp_fw_cid_1
+	#define cyttsp_cid_2()		cyttsp_fw_cid_2
+	#ifdef CY_USE_TEST_DATA
+		static struct cyttsp_gen2_xydata_t tt_gen2_testray[] = {
+		{0x00}, {0x00}, {0x04},
+		{0x4000}, {0x8000}, {0x80},
+		{0x03},
+		{0x2000}, {0x1000}, {0x00},
+		{0x00},
+		{0x00},
+		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+		{0x00},
+		{0x00}
+		};
+
+		static struct cyttsp_gen3_xydata_t tt_gen3_testray[] = {
+		{0x00}, {0x00}, {0x04},
+		{0x4000}, {0x8000}, {0x80},
+		{0x12},
+		{0x2000}, {0x1000}, {0xA0},
+		{0x00}, {0x00},
+		{0x8000}, {0x4000}, {0xB0},
+		{0x34},
+		{0x4000}, {0x1000}, {0xC0},
+		{0x00, 0x00, 0x00},
+		{0x00},
+		{0x00}
+		};
+	#endif /* CY_USE_TEST_DATA */
+
+#else
+		extern u8 g_appload_ray[];
+#endif
+
+#endif /* __CYTTSP_H__ */
-- 
1.6.3.3


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-12 20:56 ` [PATCH] i2c: cyttsp i2c touchscreen driver init submit Kevin McNeely
@ 2010-07-13  2:34   ` Christoph Fritz
  2010-08-04 16:30     ` Kevin McNeely
  2010-07-13  6:48   ` Henrik Rydberg
  2010-07-13  7:31   ` Trilok Soni
  2 siblings, 1 reply; 70+ messages in thread
From: Christoph Fritz @ 2010-07-13  2:34 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Mark Brown, Simtec Linux Team, Arnaud Patard,
	Antonio Ospite, Henrik Rydberg, linux-input, linux-kernel,
	chf.fritz

On Mon, 2010-07-12 at 13:56 -0700, Kevin McNeely wrote:
> From: Fred <fwk@ubuntu.linuxcertified.com>
> 
> This is a new touchscreen driver for the Cypress Semiconductor
> cyttsp family of devices.  This driver is for the i2c version
> of cyttsp parts.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>
> ---
>  drivers/input/touchscreen/Kconfig      |   13 +
>  drivers/input/touchscreen/Makefile     |    1 +
>  drivers/input/touchscreen/cyttsp-i2c.c | 2016 ++++++++++++++++++++++++++++++++
>  include/linux/cyttsp.h                 |  649 ++++++++++
>  4 files changed, 2679 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/input/touchscreen/cyttsp-i2c.c
>  create mode 100644 include/linux/cyttsp.h
> 
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 3b9d5e2..a7a69a0 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called tps6507x_ts.
>  
> +config TOUCHSCREEN_CYTTSP_I2C
> +	default n
> +	tristate "Cypress TTSP i2c touchscreen"
> +	depends on I2C
> +	help
> +	  Say Y here if you have a Cypress TTSP touchscreen
> +	  connected to your system's i2c bus.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called cyttsp_i2c.

below it's named cyttsp-i2c

> +
>  endif
> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
> index 497964a..2026cb8 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -47,3 +47,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
>  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
> +obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp-i2c.o
> diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
> new file mode 100644
> index 0000000..8397aa1
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp-i2c.c
> @@ -0,0 +1,2016 @@
> +/* Source for:
> + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
> + * drivers/input/touchscreen/cyttsp-i2c.c

To quote Dmitry Torokhov:
"No file names  (and especially paths) in comment blocks please - makes
harder to move stuff around."

> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Cypress reserves the right to make changes without further notice
> + * to the materials described herein. Cypress does not assume any
> + * liability arising out of the application described herein.

Sure, Cypress can engineer what they want. The warranty is already
covered by GPL.

> + *
> + * Contact Cypress Semiconductor at www.cypress.com

Maintainer or at least a email ad would be nice I think.

> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/timer.h>
> +#include <linux/workqueue.h>
> +#include <linux/byteorder/generic.h>
> +#include <linux/bitops.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif /* CONFIG_HAS_EARLYSUSPEND */
> +
> +#define CY_DECLARE_GLOBALS
> +
> +#include <linux/cyttsp.h>

Would it be possible to move cyttsp.h to the local folder?

> +
> +uint32_t cyttsp_tsdebug1 = 0xff;

why can't this be static?
why is it in the header too?

> +module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
> +
> +/* CY TTSP I2C Driver private data */
> +struct cyttsp {
> +	struct i2c_client *client;
> +	struct input_dev *input;
> +	struct work_struct work;
> +	struct timer_list timer;
> +	struct mutex mutex;
> +	char phys[32];
> +	struct cyttsp_platform_data *platform_data;
> +	u8 num_prv_st_tch;
> +	u16 act_trk[CY_NUM_TRK_ID];
> +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> +	atomic_t irq_enabled;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif /* CONFIG_HAS_EARLYSUSPEND */
> +};
> +static u8 irq_cnt;		/* comparison counter with register valuw */
> +static u32 irq_cnt_total;	/* total interrupts */
> +static u32 irq_err_cnt;		/* count number of touch interrupts with err */
> +#define CY_IRQ_CNT_MASK	0x000000FF	/* mapped for sizeof count in reg */
> +#define CY_IRQ_CNT_REG	0x00		/* tt_undef[0]=reg 0x1B - Gen3 only */
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void cyttsp_early_suspend(struct early_suspend *handler);
> +static void cyttsp_late_resume(struct early_suspend *handler);
> +#endif /* CONFIG_HAS_EARLYSUSPEND */
> +
> +static struct workqueue_struct *cyttsp_ts_wq;
> +
> +
> +/* ****************************************************************************
> + * Prototypes for static functions
> + * ************************************************************************** */

star gap, and more than 80 chars

> +static void cyttsp_xy_worker(struct work_struct *work);
> +static irqreturn_t cyttsp_irq(int irq, void *handle);
> +static int cyttsp_inlist(u16 prev_track[],
> +			u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
> +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> +			u8 *new_loc, u8 num_touches);
> +static int cyttsp_putbl(struct cyttsp *ts, int show,
> +			int show_status, int show_version, int show_cid);
> +static int __devinit cyttsp_probe(struct i2c_client *client,
> +			const struct i2c_device_id *id);
> +static int __devexit cyttsp_remove(struct i2c_client *client);
> +static int cyttsp_resume(struct i2c_client *client);
> +static int cyttsp_suspend(struct i2c_client *client, pm_message_t message);

could these prototypes be avoided?

> +
> +/* Static variables */
> +static struct cyttsp_gen3_xydata_t g_xy_data;
> +static struct cyttsp_bootloader_data_t g_bl_data;
> +static struct cyttsp_sysinfo_data_t g_sysinfo_data;
> +static const struct i2c_device_id cyttsp_id[] = {
> +	{ CY_I2C_NAME, 0 },  { }
> +};
> +static u8 bl_cmd[] = {
> +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> +	CY_BL_KEY6, CY_BL_KEY7};
> +
> +MODULE_DEVICE_TABLE(i2c, cyttsp_id);
> +
> +static struct i2c_driver cyttsp_driver = {
> +	.driver = {
> +		.name = CY_I2C_NAME,
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = cyttsp_probe,
> +	.remove = __devexit_p(cyttsp_remove),
> +	.suspend = cyttsp_suspend,
> +	.resume = cyttsp_resume,
> +	.id_table = cyttsp_id,
> +};
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver");
> +MODULE_AUTHOR("Cypress");

Why not re-factoring the whole driver to keep consistency with other
touchpad drivers?
A maintainer to contact or at least a email-ad would be nice I think.
You could use scripts/checkpatch.pl to find some warnings.

[..]



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-12 20:56 ` [PATCH] i2c: cyttsp i2c touchscreen driver init submit Kevin McNeely
  2010-07-13  2:34   ` Christoph Fritz
@ 2010-07-13  6:48   ` Henrik Rydberg
  2010-08-04 16:38     ` Kevin McNeely
  2010-07-13  7:31   ` Trilok Soni
  2 siblings, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2010-07-13  6:48 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Mark Brown, Simtec Linux Team, Arnaud Patard,
	Antonio Ospite, linux-input, linux-kernel

Kevin McNeely wrote:
> From: Fred <fwk@ubuntu.linuxcertified.com>
> 
> This is a new touchscreen driver for the Cypress Semiconductor
> cyttsp family of devices.  This driver is for the i2c version
> of cyttsp parts.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>
> ---

This driver contains too much code. I am wondering if the device actually
supports tracking id, or whether it is emulated in the driver code? If tracking
is not well supported in hardware, then please use MT protocol A and remove the
usage of ABS_MT_TRACKING_ID and the logic around it. If tracking is indeed well
supported in the hardware, then please use MT protocol B.

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-12 20:56 ` [PATCH] i2c: cyttsp i2c touchscreen driver init submit Kevin McNeely
  2010-07-13  2:34   ` Christoph Fritz
  2010-07-13  6:48   ` Henrik Rydberg
@ 2010-07-13  7:31   ` Trilok Soni
  2010-07-13  7:55     ` Dmitry Torokhov
                       ` (2 more replies)
  2 siblings, 3 replies; 70+ messages in thread
From: Trilok Soni @ 2010-07-13  7:31 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Fred, Samuel Ortiz, Eric Miao,
	Mark Brown, Simtec Linux Team, Arnaud Patard, Antonio Ospite,
	Henrik Rydberg, linux-input, linux-kernel, linux-i2c, khali,
	linux-arm-msm

Hi Kevin,

Thanks for posting this driver.

Adding Jean Delvar for i2c bits.

On 7/13/2010 2:26 AM, Kevin McNeely wrote:
> From: Fred <fwk@ubuntu.linuxcertified.com>

E-mail id looks wrong. Do you mean fwk@cypress.com?

> 
> This is a new touchscreen driver for the Cypress Semiconductor
> cyttsp family of devices.  This driver is for the i2c version
> of cyttsp parts.

Please explain in commit text which exact version of the chips this driver is supporting.
It is hard to make out that from this text.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>
> ---
>  drivers/input/touchscreen/Kconfig      |   13 +
>  drivers/input/touchscreen/Makefile     |    1 +
>  drivers/input/touchscreen/cyttsp-i2c.c | 2016 ++++++++++++++++++++++++++++++++
>  include/linux/cyttsp.h                 |  649 ++++++++++

Please move this file to include/linux/input directory.


> 
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 3b9d5e2..a7a69a0 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called tps6507x_ts.
>  
> +config TOUCHSCREEN_CYTTSP_I2C
> +	default n

Do we need to provide this if it is no by default?

> +	tristate "Cypress TTSP i2c touchscreen"
> +	depends on I2C
> +	help
> +	  Say Y here if you have a Cypress TTSP touchscreen
> +	  connected to your system's i2c bus.

What is TTSP?

> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called cyttsp_i2c.
> +
>  endif


> diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
> new file mode 100644
> index 0000000..8397aa1
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp-i2c.c
> @@ -0,0 +1,2016 @@
> +/* Source for:
> + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
> + * drivers/input/touchscreen/cyttsp-i2c.c

No file paths please. Already commented on it by Christoph.

> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Cypress reserves the right to make changes without further notice
> + * to the materials described herein. Cypress does not assume any
> + * liability arising out of the application described herein.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com

I would like Dmitry to comment on it. Dmitry?

> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/input.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/timer.h>
> +#include <linux/workqueue.h>
> +#include <linux/byteorder/generic.h>
> +#include <linux/bitops.h>
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +#include <linux/earlysuspend.h>
> +#endif /* CONFIG_HAS_EARLYSUSPEND */

We don't have early suspend support yet into the mainline kernel. Please remove this code from the driver.

> +
> +#define CY_DECLARE_GLOBALS

Could you please explain what it does?

> +
> +#include <linux/cyttsp.h>
> +
> +uint32_t cyttsp_tsdebug1 = 0xff;
> +module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
> +
> +/* CY TTSP I2C Driver private data */
> +struct cyttsp {
> +	struct i2c_client *client;
> +	struct input_dev *input;
> +	struct work_struct work;
> +	struct timer_list timer;
> +	struct mutex mutex;
> +	char phys[32];
> +	struct cyttsp_platform_data *platform_data;
> +	u8 num_prv_st_tch;
> +	u16 act_trk[CY_NUM_TRK_ID];
> +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> +	atomic_t irq_enabled;
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	struct early_suspend early_suspend;
> +#endif /* CONFIG_HAS_EARLYSUSPEND */
> +};
> +static u8 irq_cnt;		/* comparison counter with register valuw */

s/valuw/value 

> +static u32 irq_cnt_total;	/* total interrupts */
> +static u32 irq_err_cnt;		/* count number of touch interrupts with err */
> +#define CY_IRQ_CNT_MASK	0x000000FF	/* mapped for sizeof count in reg */
> +#define CY_IRQ_CNT_REG	0x00		/* tt_undef[0]=reg 0x1B - Gen3 only */
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void cyttsp_early_suspend(struct early_suspend *handler);
> +static void cyttsp_late_resume(struct early_suspend *handler);
> +#endif /* CONFIG_HAS_EARLYSUSPEND */
> +
> +static struct workqueue_struct *cyttsp_ts_wq;

Why there are so many global variables lying around?

> +
> +
> +/* ****************************************************************************
> + * Prototypes for static functions
> + * ************************************************************************** */
> +static void cyttsp_xy_worker(struct work_struct *work);
> +static irqreturn_t cyttsp_irq(int irq, void *handle);
> +static int cyttsp_inlist(u16 prev_track[],
> +			u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
> +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> +			u8 *new_loc, u8 num_touches);
> +static int cyttsp_putbl(struct cyttsp *ts, int show,
> +			int show_status, int show_version, int show_cid);
> +static int __devinit cyttsp_probe(struct i2c_client *client,
> +			const struct i2c_device_id *id);
> +static int __devexit cyttsp_remove(struct i2c_client *client);
> +static int cyttsp_resume(struct i2c_client *client);
> +static int cyttsp_suspend(struct i2c_client *client, pm_message_t message);

Please re-order the functions in the driver such a way so that you don't need have these prototypes here.

> +
> +/* Static variables */
> +static struct cyttsp_gen3_xydata_t g_xy_data;
> +static struct cyttsp_bootloader_data_t g_bl_data;
> +static struct cyttsp_sysinfo_data_t g_sysinfo_data;

again globals?

> +static const struct i2c_device_id cyttsp_id[] = {
> +	{ CY_I2C_NAME, 0 },  { }

Why dont you put ,{} at the next line.

> +};

You should not put driver name above, but it should be something like real chip name.

Say cy8ctXXX.

> +static u8 bl_cmd[] = {
> +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> +	CY_BL_KEY6, CY_BL_KEY7};

and what these keys does?

> +
> +MODULE_DEVICE_TABLE(i2c, cyttsp_id);

Why it is not with cyttsp_id above?

> +
> +static struct i2c_driver cyttsp_driver = {
> +	.driver = {
> +		.name = CY_I2C_NAME,
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = cyttsp_probe,
> +	.remove = __devexit_p(cyttsp_remove),
> +	.suspend = cyttsp_suspend,
> +	.resume = cyttsp_resume,
> +	.id_table = cyttsp_id,
> +};
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver");
> +MODULE_AUTHOR("Cypress");

MODULE_ALIAS?

> +
> +static ssize_t cyttsp_irq_status(struct device *dev,
> +				struct device_attribute *attr, char *buf)
> +{
> +	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> +	struct cyttsp *ts = i2c_get_clientdata(client);
> +	return sprintf(buf, "%u\n", atomic_read(&ts->irq_enabled));
> +}
> +
> +static ssize_t cyttsp_irq_enable(struct device *dev,
> +				struct device_attribute *attr,
> +				const char *buf, size_t size)
> +{
> +	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> +	struct cyttsp *ts = i2c_get_clientdata(client);
> +	int err = 0;
> +	unsigned long value;
> +
> +	if (size > 2)
> +		return -EINVAL;
> +
> +	err = strict_strtoul(buf, 10, &value);
> +	if (err != 0)
> +		return err;
> +
> +	switch (value) {
> +	case 0:
> +		if (atomic_cmpxchg(&ts->irq_enabled, 1, 0)) {
> +			pr_info("touch irq disabled!\n");
> +			disable_irq_nosync(ts->client->irq);
> +		}
> +		err = size;
> +		break;
> +	case 1:
> +		if (!atomic_cmpxchg(&ts->irq_enabled, 0, 1)) {
> +			pr_info("touch irq enabled!\n");
> +			enable_irq(ts->client->irq);
> +		}
> +		err = size;
> +		break;
> +	default:
> +		pr_info("cyttsp_irq_enable failed -> irq_enabled = %d\n",
> +		atomic_read(&ts->irq_enabled));
> +		err = -EINVAL;
> +		break;
> +	}
> +
> +	return err;
> +}
> +
> +static DEVICE_ATTR(irq_enable, 0777, cyttsp_irq_status, cyttsp_irq_enable);


Please explain why you are providing this sysfs entries?

> +
> +/* The cyttsp_xy_worker function reads the XY coordinates and sends them to
> + * the input layer.  It is scheduled from the interrupt (or timer).
> + */
> +void cyttsp_xy_worker(struct work_struct *work)
> +{
> +	struct cyttsp *ts = container_of(work, struct cyttsp, work);
> +	u8 id, tilt, rev_x, rev_y;
> +	u8 i, loc;
> +	u8 prv_tch;		/* number of previous touches */
> +	u8 cur_tch;	/* number of current touches */
> +	u16 tmp_trk[CY_NUM_MT_TCH_ID];
> +	u16 snd_trk[CY_NUM_MT_TCH_ID];
> +	u16 cur_trk[CY_NUM_TRK_ID];
> +	u16 cur_st_tch[CY_NUM_ST_TCH_ID];
> +	u16 cur_mt_tch[CY_NUM_MT_TCH_ID];
> +	/* if NOT CY_USE_TRACKING_ID then
> +	 * only uses CY_NUM_MT_TCH_ID positions */
> +	u16 cur_mt_pos[CY_NUM_TRK_ID][2];
> +	/* if NOT CY_USE_TRACKING_ID then
> +	 * only uses CY_NUM_MT_TCH_ID positions */
> +	u8 cur_mt_z[CY_NUM_TRK_ID];
> +	u8 curr_tool_width;
> +	u16 st_x1, st_y1;
> +	u8 st_z1;
> +	u16 st_x2, st_y2;
> +	u8 st_z2;
> +	s32 retval;
> +
> +	cyttsp_xdebug("TTSP worker start 1:\n");
> +
> +	/* get event data from CYTTSP device */
> +	i = CY_NUM_RETRY;
> +	do {
> +		retval = i2c_smbus_read_i2c_block_data(ts->client,
> +			CY_REG_BASE,
> +			sizeof(struct cyttsp_gen3_xydata_t), (u8 *)&g_xy_data);
> +	} while ((retval < CY_OK) && --i);
> +
> +	if (retval < CY_OK) {
> +		/* return immediately on
> +		 * failure to read device on the i2c bus */
> +		goto exit_xy_worker;
> +	}
> +
> +	cyttsp_xdebug("TTSP worker start 2:\n");
> +
> +	/* compare own irq counter with the device irq counter */
> +	if (ts->client->irq) {
> +		u8 host_reg;
> +		u8 cur_cnt;
> +		if (ts->platform_data->use_hndshk) {
> +
> +			host_reg = g_xy_data.hst_mode & CY_HNDSHK_BIT ?
> +				g_xy_data.hst_mode & ~CY_HNDSHK_BIT :
> +				g_xy_data.hst_mode | CY_HNDSHK_BIT;
> +			retval = i2c_smbus_write_i2c_block_data(ts->client,
> +				CY_REG_BASE, sizeof(host_reg), &host_reg);
> +		}
> +		cur_cnt = g_xy_data.tt_undef[CY_IRQ_CNT_REG];
> +		irq_cnt_total++;
> +		irq_cnt++;
> +		if (irq_cnt != cur_cnt) {
> +			irq_err_cnt++;
> +			cyttsp_debug("i_c_ER: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
> +				irq_cnt, \
> +				cur_cnt, g_xy_data.hst_mode, \
> +				(unsigned long)irq_cnt_total, \
> +				(unsigned long)irq_err_cnt);
> +		} else {
> +			cyttsp_debug("i_c_ok: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
> +				irq_cnt, \
> +				cur_cnt, g_xy_data.hst_mode, \
> +				(unsigned long)irq_cnt_total, \
> +				(unsigned long)irq_err_cnt);
> +		}
> +		irq_cnt = cur_cnt;
> +	}
> +
> +	/* Get the current num touches and return if there are no touches */
> +	if ((GET_BOOTLOADERMODE(g_xy_data.tt_mode) == 1) ||
> +		(GET_HSTMODE(g_xy_data.hst_mode) != CY_OK)) {
> +		u8 host_reg, tries;
> +		/* the TTSP device has suffered spurious reset or mode switch */
> +		cyttsp_debug( \
> +			"Spurious err opmode (tt_mode=%02X hst_mode=%02X)\n", \
> +			g_xy_data.tt_mode, g_xy_data.hst_mode);
> +		cyttsp_debug("Reset TTSP Device; Terminating active tracks\n");
> +		/* terminate all active tracks */
> +		cur_tch = CY_NTCH;
> +		/* reset TTSP part and take it back out of Bootloader mode */
> +		host_reg = CY_SOFT_RESET_MODE;
> +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> +			CY_REG_BASE,
> +			sizeof(host_reg), &host_reg);
> +		tries = 0;
> +		do {
> +			mdelay(1000);
> +
> +			/* set arg2 to non-0 to activate */
> +			retval = cyttsp_putbl(ts, 1, false, false, false);
> +		} while (!(retval < CY_OK) &&
> +			!GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
> +			!(g_bl_data.bl_file ==
> +			CY_OP_MODE + CY_LOW_PWR_MODE) &&
> +			tries++ < 10);
> +		/* switch back to operational mode */
> +		if (GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
> +			retval = i2c_smbus_write_i2c_block_data(ts->client,
> +				CY_REG_BASE,
> +				sizeof(bl_cmd), bl_cmd);
> +			tries = 0;
> +			do {
> +				mdelay(1000);
> +				cyttsp_putbl(ts, 1, false, false, false);
> +			} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
> +				tries++ < 10);
> +		}
> +		if (!(retval < CY_OK)) {
> +			host_reg = CY_OP_MODE
> +				/* + CY_LOW_PWR_MODE */;
> +			retval = i2c_smbus_write_i2c_block_data(ts->client,
> +				CY_REG_BASE,
> +				sizeof(host_reg), &host_reg);
> +			/* wait for TTSP Device to complete switch to Op mode */
> +			mdelay(1000);
> +		}
> +		goto exit_xy_worker;
> +	} else {
> +		cur_tch = GET_NUM_TOUCHES(g_xy_data.tt_stat);
> +		if (IS_LARGE_AREA(g_xy_data.tt_stat)) {
> +			/* terminate all active tracks */
> +			cur_tch = CY_NTCH;
> +			cyttsp_debug("Large obj detect (tt_stat=0x%02X). Terminate act trks\n", \
> +			    g_xy_data.tt_stat);
> +		} else if (cur_tch > CY_NUM_MT_TCH_ID) {
> +			/* if the number of fingers on the touch surface
> +			 * is more than the maximum then
> +			 * there will be no new track information
> +			 * even for the original touches.
> +			 * Therefore, terminate all active tracks.
> +			 */
> +			cur_tch = CY_NTCH;
> +			cyttsp_debug("Num touch err (tt_stat=0x%02X). Terminate act trks\n", \
> +			    g_xy_data.tt_stat);
> +		}
> +	}
> +
> +	/* set tool size */
> +	curr_tool_width = CY_SMALL_TOOL_WIDTH;
> +
> +	/* translate Gen2 interface data into comparable Gen3 data */
> +	if (ts->platform_data->gen == CY_GEN2) {
> +		struct cyttsp_gen2_xydata_t *pxy_gen2_data;
> +		pxy_gen2_data = (struct cyttsp_gen2_xydata_t *)(&g_xy_data);
> +
> +		/* use test data? */
> +		cyttsp_testdat(&g_xy_data, &tt_gen2_testray, \
> +			sizeof(struct cyttsp_gen3_xydata_t));
> +
> +		if (pxy_gen2_data->evnt_idx == CY_GEN2_NOTOUCH) {
> +			cur_tch = 0;
> +		} else if (cur_tch == CY_GEN2_GHOST) {
> +			cur_tch = 0;
> +		} else if (cur_tch == CY_GEN2_2TOUCH) {
> +			/* stuff artificial track ID1 and ID2 */
> +			g_xy_data.touch12_id = 0x12;
> +			g_xy_data.z1 = CY_MAXZ;
> +			g_xy_data.z2 = CY_MAXZ;
> +			cur_tch--;			/* 2 touches */
> +		} else if (cur_tch == CY_GEN2_1TOUCH) {
> +			/* stuff artificial track ID1 and ID2 */
> +			g_xy_data.touch12_id = 0x12;
> +			g_xy_data.z1 = CY_MAXZ;
> +			g_xy_data.z2 = CY_NTCH;
> +			if (pxy_gen2_data->evnt_idx == CY_GEN2_TOUCH2) {
> +				/* push touch 2 data into touch1
> +				 * (first finger up; second finger down) */
> +				/* stuff artificial track ID1 for touch2 info */
> +				g_xy_data.touch12_id = 0x20;
> +				/* stuff touch 1 with touch 2 coordinate data */
> +				g_xy_data.x1 = g_xy_data.x2;
> +				g_xy_data.y1 = g_xy_data.y2;
> +			}
> +		} else {
> +			cur_tch = 0;
> +		}
> +	} else {
> +		/* use test data? */
> +		cyttsp_testdat(&g_xy_data, &tt_gen3_testray, \
> +			sizeof(struct cyttsp_gen3_xydata_t));
> +	}
> +
> +
> +
> +	/* clear current active track ID array and count previous touches */
> +	for (id = 0, prv_tch = CY_NTCH;
> +		id < CY_NUM_TRK_ID; id++) {
> +		cur_trk[id] = CY_NTCH;
> +		prv_tch += ts->act_trk[id];
> +	}
> +
> +	/* send no events if no previous touches and no new touches */
> +	if ((prv_tch == CY_NTCH) &&
> +		((cur_tch == CY_NTCH) ||
> +		(cur_tch > CY_NUM_MT_TCH_ID))) {
> +		goto exit_xy_worker;
> +	}
> +
> +	cyttsp_debug("prev=%d  curr=%d\n", prv_tch, cur_tch);
> +
> +	for (id = 0; id < CY_NUM_ST_TCH_ID; id++) {
> +		/* clear current single touches array */
> +		cur_st_tch[id] = CY_IGNR_TCH;
> +	}
> +
> +	/* clear single touch positions */
> +	st_x1 = CY_NTCH;
> +	st_y1 = CY_NTCH;
> +	st_z1 = CY_NTCH;
> +	st_x2 = CY_NTCH;
> +	st_y2 = CY_NTCH;
> +	st_z2 = CY_NTCH;
> +
> +	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +		/* clear current multi-touches array and
> +		 * multi-touch positions/z */
> +		cur_mt_tch[id] = CY_IGNR_TCH;
> +	}
> +
> +	if (ts->platform_data->use_trk_id) {
> +		for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +			cur_mt_pos[id][CY_XPOS] = 0;
> +			cur_mt_pos[id][CY_YPOS] = 0;
> +			cur_mt_z[id] = 0;
> +		}
> +	} else {
> +		for (id = 0; id < CY_NUM_TRK_ID; id++) {
> +			cur_mt_pos[id][CY_XPOS] = 0;
> +			cur_mt_pos[id][CY_YPOS] = 0;
> +			cur_mt_z[id] = 0;
> +		}
> +	}
> +
> +	/* Determine if display is tilted */
> +	if (FLIP_DATA(ts->platform_data->flags))
> +		tilt = true;
> +	else
> +		tilt = false;
> +
> +	/* Check for switch in origin */
> +	if (REVERSE_X(ts->platform_data->flags))
> +		rev_x = true;
> +	else
> +		rev_x = false;
> +
> +	if (REVERSE_Y(ts->platform_data->flags))
> +		rev_y = true;
> +	else
> +		rev_y = false;
> +
> +	if (cur_tch) {
> +		struct cyttsp_gen2_xydata_t *pxy_gen2_data;
> +		struct cyttsp_gen3_xydata_t *pxy_gen3_data;
> +		switch (ts->platform_data->gen) {
> +		case CY_GEN2: {
> +			pxy_gen2_data =
> +				(struct cyttsp_gen2_xydata_t *)(&g_xy_data);
> +			cyttsp_xdebug("TTSP Gen2 report:\n");
> +			cyttsp_xdebug("%02X %02X %02X\n", \
> +				pxy_gen2_data->hst_mode, \
> +				pxy_gen2_data->tt_mode, \
> +				pxy_gen2_data->tt_stat);
> +			cyttsp_xdebug("%04X %04X %02X  %02X\n", \
> +				pxy_gen2_data->x1, \
> +				pxy_gen2_data->y1, \
> +				pxy_gen2_data->z1, \
> +				pxy_gen2_data->evnt_idx);
> +			cyttsp_xdebug("%04X %04X %02X\n", \
> +				pxy_gen2_data->x2, \
> +				pxy_gen2_data->y2, \
> +				pxy_gen2_data->tt_undef1);
> +			cyttsp_xdebug("%02X %02X %02X\n", \
> +				pxy_gen2_data->gest_cnt, \
> +				pxy_gen2_data->gest_id, \
> +				pxy_gen2_data->gest_set);
> +			break;
> +		}
> +		case CY_GEN3:
> +		default: {
> +			pxy_gen3_data =
> +				(struct cyttsp_gen3_xydata_t *)(&g_xy_data);
> +			cyttsp_xdebug("TTSP Gen3 report:\n");
> +			cyttsp_xdebug("%02X %02X %02X\n", \
> +				pxy_gen3_data->hst_mode,
> +				pxy_gen3_data->tt_mode,
> +				pxy_gen3_data->tt_stat);
> +			cyttsp_xdebug("%04X %04X %02X  %02X", \
> +				pxy_gen3_data->x1,
> +				pxy_gen3_data->y1,
> +				pxy_gen3_data->z1, \
> +				pxy_gen3_data->touch12_id);
> +			cyttsp_xdebug("%04X %04X %02X\n", \
> +				pxy_gen3_data->x2, \
> +				pxy_gen3_data->y2, \
> +				pxy_gen3_data->z2);
> +			cyttsp_xdebug("%02X %02X %02X\n", \
> +				pxy_gen3_data->gest_cnt, \
> +				pxy_gen3_data->gest_id, \
> +				pxy_gen3_data->gest_set);
> +			cyttsp_xdebug("%04X %04X %02X  %02X\n", \
> +				pxy_gen3_data->x3, \
> +				pxy_gen3_data->y3, \
> +				pxy_gen3_data->z3, \
> +				pxy_gen3_data->touch34_id);
> +			cyttsp_xdebug("%04X %04X %02X\n", \
> +				pxy_gen3_data->x4, \
> +				pxy_gen3_data->y4, \
> +				pxy_gen3_data->z4);
> +			break;
> +		}
> +		}
> +	}
> +
> +	/* process the touches */
> +	switch (cur_tch) {
> +	case 4: {
> +		g_xy_data.x4 = be16_to_cpu(g_xy_data.x4);
> +		g_xy_data.y4 = be16_to_cpu(g_xy_data.y4);
> +		if (tilt)
> +			FLIP_XY(g_xy_data.x4, g_xy_data.y4);
> +
> +		if (rev_x) {
> +			g_xy_data.x4 =
> +				INVERT_X(g_xy_data.x4, ts->platform_data->maxx);
> +		}
> +		if (rev_y) {
> +			g_xy_data.y4 =
> +				INVERT_X(g_xy_data.y4, ts->platform_data->maxy);
> +		}
> +		id = GET_TOUCH4_ID(g_xy_data.touch34_id);
> +		if (ts->platform_data->use_trk_id) {
> +			cur_mt_pos[CY_MT_TCH4_IDX][CY_XPOS] =
> +				g_xy_data.x4;
> +			cur_mt_pos[CY_MT_TCH4_IDX][CY_YPOS] =
> +				g_xy_data.y4;
> +			cur_mt_z[CY_MT_TCH4_IDX] = g_xy_data.z4;
> +		} else {
> +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x4;
> +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y4;
> +			cur_mt_z[id] = g_xy_data.z4;
> +		}
> +		cur_mt_tch[CY_MT_TCH4_IDX] = id;
> +		cur_trk[id] = CY_TCH;
> +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> +			CY_NUM_TRK_ID) {
> +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> +				st_x1 = g_xy_data.x4;
> +				st_y1 = g_xy_data.y4;
> +				st_z1 = g_xy_data.z4;
> +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
> +				st_x2 = g_xy_data.x4;
> +				st_y2 = g_xy_data.y4;
> +				st_z2 = g_xy_data.z4;
> +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> +			}
> +		}
> +		cyttsp_xdebug("4th XYZ:% 3d,% 3d,% 3d  ID:% 2d\n\n", \
> +			g_xy_data.x4, g_xy_data.y4, g_xy_data.z4, \
> +			(g_xy_data.touch34_id & 0x0F));
> +		/* do not break */
> +	}
> +	case 3: {
> +		g_xy_data.x3 = be16_to_cpu(g_xy_data.x3);
> +		g_xy_data.y3 = be16_to_cpu(g_xy_data.y3);
> +		if (tilt)
> +			FLIP_XY(g_xy_data.x3, g_xy_data.y3);
> +
> +		if (rev_x) {
> +			g_xy_data.x3 =
> +				INVERT_X(g_xy_data.x3, ts->platform_data->maxx);
> +		}
> +		if (rev_y) {
> +			g_xy_data.y3 =
> +				INVERT_X(g_xy_data.y3, ts->platform_data->maxy);
> +		}
> +		id = GET_TOUCH3_ID(g_xy_data.touch34_id);
> +		if (ts->platform_data->use_trk_id) {
> +			cur_mt_pos[CY_MT_TCH3_IDX][CY_XPOS] =
> +				g_xy_data.x3;
> +			cur_mt_pos[CY_MT_TCH3_IDX][CY_YPOS] =
> +				g_xy_data.y3;
> +			cur_mt_z[CY_MT_TCH3_IDX] = g_xy_data.z3;
> +		} else {
> +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x3;
> +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y3;
> +			cur_mt_z[id] = g_xy_data.z3;
> +		}
> +		cur_mt_tch[CY_MT_TCH3_IDX] = id;
> +		cur_trk[id] = CY_TCH;
> +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> +			CY_NUM_TRK_ID) {
> +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> +				st_x1 = g_xy_data.x3;
> +				st_y1 = g_xy_data.y3;
> +				st_z1 = g_xy_data.z3;
> +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
> +				st_x2 = g_xy_data.x3;
> +				st_y2 = g_xy_data.y3;
> +				st_z2 = g_xy_data.z3;
> +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> +			}
> +		}
> +		cyttsp_xdebug("3rd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
> +			g_xy_data.x3, g_xy_data.y3, g_xy_data.z3, \
> +			((g_xy_data.touch34_id >> 4) & 0x0F));
> +		/* do not break */
> +	}
> +	case 2: {
> +		g_xy_data.x2 = be16_to_cpu(g_xy_data.x2);
> +		g_xy_data.y2 = be16_to_cpu(g_xy_data.y2);
> +		if (tilt)
> +			FLIP_XY(g_xy_data.x2, g_xy_data.y2);
> +
> +		if (rev_x) {
> +			g_xy_data.x2 =
> +				INVERT_X(g_xy_data.x2, ts->platform_data->maxx);
> +		}
> +		if (rev_y) {
> +			g_xy_data.y2 =
> +				INVERT_X(g_xy_data.y2, ts->platform_data->maxy);
> +		}
> +		id = GET_TOUCH2_ID(g_xy_data.touch12_id);
> +		if (ts->platform_data->use_trk_id) {
> +			cur_mt_pos[CY_MT_TCH2_IDX][CY_XPOS] =
> +				g_xy_data.x2;
> +			cur_mt_pos[CY_MT_TCH2_IDX][CY_YPOS] =
> +				g_xy_data.y2;
> +			cur_mt_z[CY_MT_TCH2_IDX] = g_xy_data.z2;
> +		} else {
> +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x2;
> +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y2;
> +			cur_mt_z[id] = g_xy_data.z2;
> +		}
> +		cur_mt_tch[CY_MT_TCH2_IDX] = id;
> +		cur_trk[id] = CY_TCH;
> +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> +			CY_NUM_TRK_ID) {
> +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> +				st_x1 = g_xy_data.x2;
> +				st_y1 = g_xy_data.y2;
> +				st_z1 = g_xy_data.z2;
> +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
> +				st_x2 = g_xy_data.x2;
> +				st_y2 = g_xy_data.y2;
> +				st_z2 = g_xy_data.z2;
> +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> +			}
> +		}
> +		cyttsp_xdebug("2nd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
> +			g_xy_data.x2, g_xy_data.y2, g_xy_data.z2, \
> +			(g_xy_data.touch12_id & 0x0F));
> +		/* do not break */
> +	}
> +	case 1:	{
> +		g_xy_data.x1 = be16_to_cpu(g_xy_data.x1);
> +		g_xy_data.y1 = be16_to_cpu(g_xy_data.y1);
> +		if (tilt)
> +			FLIP_XY(g_xy_data.x1, g_xy_data.y1);
> +
> +		if (rev_x) {
> +			g_xy_data.x1 =
> +				INVERT_X(g_xy_data.x1, ts->platform_data->maxx);
> +		}
> +		if (rev_y) {
> +			g_xy_data.y1 =
> +				INVERT_X(g_xy_data.y1, ts->platform_data->maxy);
> +		}
> +		id = GET_TOUCH1_ID(g_xy_data.touch12_id);
> +		if (ts->platform_data->use_trk_id) {
> +			cur_mt_pos[CY_MT_TCH1_IDX][CY_XPOS] =
> +				g_xy_data.x1;
> +			cur_mt_pos[CY_MT_TCH1_IDX][CY_YPOS] =
> +				g_xy_data.y1;
> +			cur_mt_z[CY_MT_TCH1_IDX] = g_xy_data.z1;
> +		} else {
> +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x1;
> +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y1;
> +			cur_mt_z[id] = g_xy_data.z1;
> +		}
> +		cur_mt_tch[CY_MT_TCH1_IDX] = id;
> +		cur_trk[id] = CY_TCH;
> +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> +			CY_NUM_TRK_ID) {
> +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> +				st_x1 = g_xy_data.x1;
> +				st_y1 = g_xy_data.y1;
> +				st_z1 = g_xy_data.z1;
> +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
> +				st_x2 = g_xy_data.x1;
> +				st_y2 = g_xy_data.y1;
> +				st_z2 = g_xy_data.z1;
> +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> +			}
> +		}
> +		cyttsp_xdebug("1st XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
> +			g_xy_data.x1, g_xy_data.y1, g_xy_data.z1, \
> +			((g_xy_data.touch12_id >> 4) & 0x0F));
> +		break;
> +	}
> +	case 0:
> +	default:{
> +		break;
> +	}
> +	}
> +
> +	/* handle Single Touch signals */
> +	if (ts->platform_data->use_st) {
> +		cyttsp_xdebug("ST STEP 0 - ST1 ID=%d  ST2 ID=%d\n", \
> +			cur_st_tch[CY_ST_FNGR1_IDX], \
> +			cur_st_tch[CY_ST_FNGR2_IDX]);
> +		if (cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) {
> +			/* reassign finger 1 and 2 positions to new tracks */
> +			if (cur_tch > 0) {
> +				/* reassign st finger1 */
> +				if (ts->platform_data->use_trk_id) {
> +					id = CY_MT_TCH1_IDX;
> +					cur_st_tch[CY_ST_FNGR1_IDX] = cur_mt_tch[id];
> +				} else {
> +					id = GET_TOUCH1_ID(g_xy_data.touch12_id);
> +					cur_st_tch[CY_ST_FNGR1_IDX] = id;
> +				}
> +				st_x1 = cur_mt_pos[id][CY_XPOS];
> +				st_y1 = cur_mt_pos[id][CY_YPOS];
> +				st_z1 = cur_mt_z[id];
> +				cyttsp_xdebug("ST STEP 1 - ST1 ID=%3d\n", \
> +					cur_st_tch[CY_ST_FNGR1_IDX]);
> +				if ((cur_tch > 1) &&
> +					(cur_st_tch[CY_ST_FNGR2_IDX] >
> +					CY_NUM_TRK_ID)) {
> +					/* reassign st finger2 */
> +					if (cur_tch > 1) {
> +						if (ts->platform_data->use_trk_id) {
> +							id = CY_MT_TCH2_IDX;
> +							cur_st_tch[CY_ST_FNGR2_IDX] = cur_mt_tch[id];
> +						} else {
> +							id = GET_TOUCH2_ID(g_xy_data.touch12_id);
> +							cur_st_tch[CY_ST_FNGR2_IDX] = id;
> +						}
> +						st_x2 = cur_mt_pos[id][CY_XPOS];
> +						st_y2 = cur_mt_pos[id][CY_YPOS];
> +						st_z2 = cur_mt_z[id];
> +						cyttsp_xdebug("ST STEP 2 - ST2 ID=%3d\n", \
> +							cur_st_tch[CY_ST_FNGR2_IDX]);
> +					}
> +				}
> +			}
> +		} else if (cur_st_tch[CY_ST_FNGR2_IDX] > CY_NUM_TRK_ID) {
> +			if (cur_tch > 1) {
> +				/* reassign st finger2 */
> +				if (ts->platform_data->use_trk_id) {
> +					/* reassign st finger2 */
> +					id = CY_MT_TCH2_IDX;
> +					cur_st_tch[CY_ST_FNGR2_IDX] =
> +						cur_mt_tch[id];
> +				} else {
> +					/* reassign st finger2 */
> +					id = GET_TOUCH2_ID(g_xy_data.touch12_id);
> +					cur_st_tch[CY_ST_FNGR2_IDX] = id;
> +				}
> +				st_x2 = cur_mt_pos[id][CY_XPOS];
> +				st_y2 = cur_mt_pos[id][CY_YPOS];
> +				st_z2 = cur_mt_z[id];
> +				cyttsp_xdebug("ST STEP 3 - ST2 ID=%3d\n", \
> +					cur_st_tch[CY_ST_FNGR2_IDX]);
> +			}
> +		}
> +		/* if the 1st touch is missing and there is a 2nd touch,
> +		 * then set the 1st touch to 2nd touch and terminate 2nd touch
> +		 */
> +		if ((cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) &&
> +		    (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID)) {
> +			st_x1 = st_x2;
> +			st_y1 = st_y2;
> +			st_z1 = st_z2;
> +			cur_st_tch[CY_ST_FNGR1_IDX] =
> +				cur_st_tch[CY_ST_FNGR2_IDX];
> +			cur_st_tch[CY_ST_FNGR2_IDX] =
> +				CY_IGNR_TCH;
> +		}
> +		/* if the 2nd touch ends up equal to the 1st touch,
> +		 * then just report a single touch */
> +		if (cur_st_tch[CY_ST_FNGR1_IDX] ==
> +			cur_st_tch[CY_ST_FNGR2_IDX]) {
> +			cur_st_tch[CY_ST_FNGR2_IDX] =
> +				CY_IGNR_TCH;
> +		}
> +		/* set Single Touch current event signals */
> +		if (cur_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) {
> +			input_report_abs(ts->input,
> +				ABS_X, st_x1);
> +			input_report_abs(ts->input,
> +				ABS_Y, st_y1);
> +			input_report_abs(ts->input,
> +				ABS_PRESSURE, st_z1);
> +			input_report_key(ts->input,
> +				BTN_TOUCH,
> +				CY_TCH);
> +			input_report_abs(ts->input,
> +				ABS_TOOL_WIDTH,
> +				curr_tool_width);
> +			cyttsp_debug("ST->F1:%3d X:%3d Y:%3d Z:%3d\n", \
> +				cur_st_tch[CY_ST_FNGR1_IDX], \
> +				st_x1, st_y1, st_z1);
> +			if (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID) {
> +				input_report_key(ts->input, BTN_2, CY_TCH);
> +				input_report_abs(ts->input, ABS_HAT0X, st_x2);
> +				input_report_abs(ts->input, ABS_HAT0Y, st_y2);
> +				cyttsp_debug("ST->F2:%3d X:%3d Y:%3d Z:%3d\n", \
> +					cur_st_tch[CY_ST_FNGR2_IDX],
> +					st_x2, st_y2, st_z2);
> +			} else {
> +				input_report_key(ts->input,
> +					BTN_2,
> +					CY_NTCH);
> +			}
> +		} else {
> +			input_report_abs(ts->input, ABS_PRESSURE, CY_NTCH);
> +			input_report_key(ts->input, BTN_TOUCH, CY_NTCH);
> +			input_report_key(ts->input, BTN_2, CY_NTCH);
> +		}
> +		/* update platform data for the current single touch info */
> +		ts->prv_st_tch[CY_ST_FNGR1_IDX] = cur_st_tch[CY_ST_FNGR1_IDX];
> +		ts->prv_st_tch[CY_ST_FNGR2_IDX] = cur_st_tch[CY_ST_FNGR2_IDX];
> +
> +	}
> +
> +	/* handle Multi-touch signals */
> +	if (ts->platform_data->use_mt) {
> +		if (ts->platform_data->use_trk_id) {
> +			/* terminate any previous touch where the track
> +			 * is missing from the current event */
> +			for (id = 0; id < CY_NUM_TRK_ID; id++) {
> +				if ((ts->act_trk[id] != CY_NTCH) &&
> +					(cur_trk[id] == CY_NTCH)) {
> +					input_report_abs(ts->input,
> +						ABS_MT_TRACKING_ID,
> +						id);
> +					input_report_abs(ts->input,
> +						ABS_MT_TOUCH_MAJOR,
> +						CY_NTCH);
> +					input_report_abs(ts->input,
> +						ABS_MT_WIDTH_MAJOR,
> +						curr_tool_width);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_X,
> +						ts->prv_mt_pos[id][CY_XPOS]);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_Y,
> +						ts->prv_mt_pos[id][CY_YPOS]);
> +					CY_MT_SYNC(ts->input);
> +					ts->act_trk[id] = CY_NTCH;
> +					ts->prv_mt_pos[id][CY_XPOS] = 0;
> +					ts->prv_mt_pos[id][CY_YPOS] = 0;
> +				}
> +			}
> +			/* set Multi-Touch current event signals */
> +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +				if (cur_mt_tch[id] < CY_NUM_TRK_ID) {
> +					input_report_abs(ts->input,
> +						ABS_MT_TRACKING_ID,
> +						cur_mt_tch[id]);
> +					input_report_abs(ts->input,
> +						ABS_MT_TOUCH_MAJOR,
> +						cur_mt_z[id]);
> +					input_report_abs(ts->input,
> +						ABS_MT_WIDTH_MAJOR,
> +						curr_tool_width);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_X,
> +						cur_mt_pos[id][CY_XPOS]);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_Y,
> +						cur_mt_pos[id][CY_YPOS]);
> +					CY_MT_SYNC(ts->input);
> +					ts->act_trk[id] = CY_TCH;
> +					ts->prv_mt_pos[id][CY_XPOS] =
> +						cur_mt_pos[id][CY_XPOS];
> +					ts->prv_mt_pos[id][CY_YPOS] =
> +						cur_mt_pos[id][CY_YPOS];
> +				}
> +			}
> +		} else {
> +			/* set temporary track array elements to voids */
> +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +				tmp_trk[id] = CY_IGNR_TCH;
> +				snd_trk[id] = CY_IGNR_TCH;
> +			}
> +
> +			/* get what is currently active */
> +			for (i = 0, id = 0;
> +				id < CY_NUM_TRK_ID && i < CY_NUM_MT_TCH_ID;
> +				id++) {
> +				if (cur_trk[id] == CY_TCH) {
> +					/* only incr counter if track found */
> +					tmp_trk[i] = id;
> +					i++;
> +				}
> +			}
> +			cyttsp_xdebug("T1: t0=%d, t1=%d, t2=%d, t3=%d\n", \
> +				tmp_trk[0], tmp_trk[1], tmp_trk[2], \
> +				tmp_trk[3]);
> +			cyttsp_xdebug("T1: p0=%d, p1=%d, p2=%d, p3=%d\n", \
> +				ts->prv_mt_tch[0], ts->prv_mt_tch[1], \
> +				ts->prv_mt_tch[2], ts->prv_mt_tch[3]);
> +
> +			/* pack in still active previous touches */
> +			for (id = 0, prv_tch = 0;
> +				id < CY_NUM_MT_TCH_ID; id++) {
> +				if (tmp_trk[id] < CY_NUM_TRK_ID) {
> +					if (cyttsp_inlist(ts->prv_mt_tch,
> +						tmp_trk[id], &loc,
> +						CY_NUM_MT_TCH_ID)) {
> +						loc &= CY_NUM_MT_TCH_ID - 1;
> +						snd_trk[loc] = tmp_trk[id];
> +						prv_tch++;
> +						cyttsp_xdebug("inlist s[%d]=%d t[%d]=%d l=%d p=%d\n", \
> +							loc, snd_trk[loc], \
> +							id, tmp_trk[id], \
> +							loc, prv_tch);
> +					} else {
> +						cyttsp_xdebug("not inlist s[%d]=%d t[%d]=%d l=%d \n", \
> +							id, snd_trk[id], \
> +							id, tmp_trk[id], \
> +							loc);
> +					}
> +				}
> +			}
> +			cyttsp_xdebug("S1: s0=%d, s1=%d, s2=%d, s3=%d p=%d\n", \
> +				snd_trk[0], snd_trk[1], snd_trk[2], \
> +				snd_trk[3], prv_tch);
> +
> +			/* pack in new touches */
> +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +				if (tmp_trk[id] < CY_NUM_TRK_ID) {
> +					if (!cyttsp_inlist(snd_trk, tmp_trk[id], &loc, CY_NUM_MT_TCH_ID)) {
> +						cyttsp_xdebug("not inlist t[%d]=%d l=%d\n", \
> +							id, tmp_trk[id], loc);
> +						if (cyttsp_next_avail_inlist(snd_trk, &loc, CY_NUM_MT_TCH_ID)) {
> +							loc &= CY_NUM_MT_TCH_ID - 1;
> +							snd_trk[loc] = tmp_trk[id];
> +							cyttsp_xdebug("put inlist s[%d]=%d t[%d]=%d\n",
> +								loc, snd_trk[loc], id, tmp_trk[id]);
> +						}
> +					} else {
> +						cyttsp_xdebug("is in list s[%d]=%d t[%d]=%d loc=%d\n", \
> +							id, snd_trk[id], id, tmp_trk[id], loc);
> +					}
> +				}
> +			}
> +			cyttsp_xdebug("S2: s0=%d, s1=%d, s2=%d, s3=%d\n", \
> +				snd_trk[0], snd_trk[1],
> +				snd_trk[2], snd_trk[3]);
> +
> +			/* sync motion event signals for each current touch */
> +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +				/* z will either be 0 (NOTOUCH) or
> +				 * some pressure (TOUCH) */
> +				cyttsp_xdebug("MT0 prev[%d]=%d temp[%d]=%d send[%d]=%d\n", \
> +					id, ts->prv_mt_tch[id], \
> +					id, tmp_trk[id], \
> +					id, snd_trk[id]);
> +				if (snd_trk[id] < CY_NUM_TRK_ID) {
> +					input_report_abs(ts->input,
> +						ABS_MT_TOUCH_MAJOR,
> +						cur_mt_z[snd_trk[id]]);
> +					input_report_abs(ts->input,
> +						ABS_MT_WIDTH_MAJOR,
> +						curr_tool_width);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_X,
> +						cur_mt_pos[snd_trk[id]][CY_XPOS]);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_Y,
> +						cur_mt_pos[snd_trk[id]][CY_YPOS]);
> +					CY_MT_SYNC(ts->input);
> +					cyttsp_debug("MT1->TID:%2d X:%3d Y:%3d Z:%3d touch-sent\n", \
> +						snd_trk[id], \
> +						cur_mt_pos[snd_trk[id]][CY_XPOS], \
> +						cur_mt_pos[snd_trk[id]][CY_YPOS], \
> +						cur_mt_z[snd_trk[id]]);
> +				} else if (ts->prv_mt_tch[id] < CY_NUM_TRK_ID) {
> +					/* void out this touch */
> +					input_report_abs(ts->input,
> +						ABS_MT_TOUCH_MAJOR,
> +						CY_NTCH);
> +					input_report_abs(ts->input,
> +						ABS_MT_WIDTH_MAJOR,
> +						curr_tool_width);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_X,
> +						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS]);
> +					input_report_abs(ts->input,
> +						ABS_MT_POSITION_Y,
> +						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS]);
> +					CY_MT_SYNC(ts->input);
> +					cyttsp_debug("MT2->TID:%2d X:%3d Y:%3d Z:%3d lift off-sent\n", \
> +						ts->prv_mt_tch[id], \
> +						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS], \
> +						ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS], \
> +						CY_NTCH);
> +				} else {
> +					/* do not stuff any signals for this
> +					 * previously and currently
> +					 * void touches */
> +					cyttsp_xdebug("MT3->send[%d]=%d - No touch - NOT sent\n", \
> +							id, snd_trk[id]);
> +				}
> +			}
> +
> +			/* save current posted tracks to
> +			 * previous track memory */
> +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +				ts->prv_mt_tch[id] = snd_trk[id];
> +				ts->prv_mt_pos[snd_trk[id]][CY_XPOS] =
> +					cur_mt_pos[snd_trk[id]][CY_XPOS];
> +				ts->prv_mt_pos[snd_trk[id]][CY_YPOS] =
> +					cur_mt_pos[snd_trk[id]][CY_YPOS];
> +				cyttsp_xdebug("MT4->TID:%2d X:%3d Y:%3d Z:%3d save for previous\n", \
> +					snd_trk[id], \
> +					ts->prv_mt_pos[snd_trk[id]][CY_XPOS], \
> +					ts->prv_mt_pos[snd_trk[id]][CY_YPOS], \
> +					CY_NTCH);
> +			}
> +			for (id = 0; id < CY_NUM_TRK_ID; id++)
> +				ts->act_trk[id] = CY_NTCH;
> +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> +				if (snd_trk[id] < CY_NUM_TRK_ID)
> +					ts->act_trk[snd_trk[id]] = CY_TCH;
> +			}
> +		}
> +	}
> +
> +	/* handle gestures */
> +	if (ts->platform_data->use_gestures) {
> +		if (g_xy_data.gest_id) {
> +			input_report_key(ts->input,
> +				BTN_3, CY_TCH);
> +			input_report_abs(ts->input,
> +				ABS_HAT1X, g_xy_data.gest_id);
> +			input_report_abs(ts->input,
> +				ABS_HAT2Y, g_xy_data.gest_cnt);
> +		}
> +	}
> +
> +	/* signal the view motion event */
> +	input_sync(ts->input);
> +
> +	for (id = 0; id < CY_NUM_TRK_ID; id++) {
> +		/* update platform data for the current MT information */
> +		ts->act_trk[id] = cur_trk[id];
> +	}
> +
> +exit_xy_worker:
> +	if (cyttsp_disable_touch) {
> +		/* Turn off the touch interrupts */
> +		cyttsp_debug("Not enabling touch\n");
> +	} else {
> +		if (ts->client->irq == 0) {
> +			/* restart event timer */
> +			mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
> +		} else {
> +			/* re-enable the interrupt after processing */
> +			enable_irq(ts->client->irq);
> +		}
> +	}
> +	return;
> +}
> +
> +static int cyttsp_inlist(u16 prev_track[], u8 cur_trk_id,
> +			u8 *prev_loc, u8 num_touches)
> +{

return could be "bool" instead of "int" right?

> +	u8 id = 0;
> +
> +	*prev_loc = CY_IGNR_TCH;
> +
> +		cyttsp_xdebug("IN p[%d]=%d c=%d n=%d loc=%d\n", \
> +			id, prev_track[id], cur_trk_id, \
> +			num_touches, *prev_loc);

Indentation problem.

> +	for (id = 0, *prev_loc = CY_IGNR_TCH;
> +		(id < num_touches); id++) {
> +		cyttsp_xdebug("p[%d]=%d c=%d n=%d loc=%d\n", \
> +			id, prev_track[id], cur_trk_id, \
> +			num_touches, *prev_loc);
> +		if (prev_track[id] == cur_trk_id) {
> +			*prev_loc = id;
> +			break;
> +		}
> +	}
> +	cyttsp_xdebug("OUT p[%d]=%d c=%d n=%d loc=%d\n", \
> +		id, prev_track[id], cur_trk_id, num_touches, *prev_loc);
> +
> +	return ((*prev_loc < CY_NUM_TRK_ID) ? true : false);
> +}
> +
> +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> +			u8 *new_loc, u8 num_touches)
> +{

return could be "bool" instead of "int" right?

> +	u8 id;
> +
> +	for (id = 0, *new_loc = CY_IGNR_TCH;
> +		(id < num_touches); id++) {
> +		if (cur_trk[id] > CY_NUM_TRK_ID) {
> +			*new_loc = id;
> +			break;
> +		}
> +	}
> +
> +	return ((*new_loc < CY_NUM_TRK_ID) ? true : false);
> +}
> +
> +/* Timer function used as dummy interrupt driver */
> +static void cyttsp_timer(unsigned long handle)
> +{
> +	struct cyttsp *ts = (struct cyttsp *) handle;
> +
> +	cyttsp_xdebug("TTSP Device timer event\n");
> +
> +	/* schedule motion signal handling */
> +	queue_work(cyttsp_ts_wq, &ts->work);
> +
> +	return;
> +}
> +
> +
> +
> +/* ************************************************************************
> + * ISR function. This function is general, initialized in drivers init
> + * function
> + * ************************************************************************ */
> +static irqreturn_t cyttsp_irq(int irq, void *handle)
> +{
> +	struct cyttsp *ts = (struct cyttsp *) handle;
> +
> +	cyttsp_xdebug("%s: Got IRQ\n", CY_I2C_NAME);
> +
> +	/* disable further interrupts until this interrupt is processed */
> +	disable_irq_nosync(ts->client->irq);

As indicated below please use request_threaded_irq(..).


> +
> +	/* schedule motion signal handling */
> +	queue_work(cyttsp_ts_wq, &ts->work);
> +	return IRQ_HANDLED;
> +}
> +
> +/* ************************************************************************
> + * Probe initialization functions
> + * ************************************************************************ */
> +static int cyttsp_putbl(struct cyttsp *ts, int show,
> +			int show_status, int show_version, int show_cid)
> +{
> +	int retval = CY_OK;
> +
> +	int num_bytes = (show_status * 3) + (show_version * 6) + (show_cid * 3);
> +
> +	if (show_cid)
> +		num_bytes = sizeof(struct cyttsp_bootloader_data_t);
> +	else if (show_version)
> +		num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 3;
> +	else
> +		num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 9;
> +
> +	if (show) {
> +		retval = i2c_smbus_read_i2c_block_data(ts->client,
> +			CY_REG_BASE, num_bytes, (u8 *)&g_bl_data);
> +		if (show_status) {
> +			cyttsp_debug("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X\n", \
> +				show, \
> +				g_bl_data.bl_file, \
> +				g_bl_data.bl_status, \
> +				g_bl_data.bl_error, \
> +				g_bl_data.blver_hi, g_bl_data.blver_lo, \
> +				g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo);
> +		}
> +		if (show_version) {
> +			cyttsp_debug("BL%d: ttspver=0x%02X%02X appid=0x%02X%02X appver=0x%02X%02X\n", \
> +				show, \
> +				g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
> +				g_bl_data.appid_hi, g_bl_data.appid_lo, \
> +				g_bl_data.appver_hi, g_bl_data.appver_lo);
> +		}
> +		if (show_cid) {
> +			cyttsp_debug("BL%d: cid=0x%02X%02X%02X\n", \
> +				show, \
> +				g_bl_data.cid_0, \
> +				g_bl_data.cid_1, \
> +				g_bl_data.cid_2);
> +		}
> +		mdelay(CY_DLY_DFLT);
> +	}
> +
> +	return retval;
> +}
> +
> +#ifdef CY_INCLUDE_LOAD_FILE

Could you please explain what is the use of this #define? 

Are we loading any firmware? Please explain why we can't use request_firware(...).

> +#define CY_MAX_I2C_LEN	256
> +#define CY_MAX_TRY		10
> +#define CY_BL_PAGE_SIZE	16
> +#define CY_BL_NUM_PAGES	5
> +static int cyttsp_i2c_wr_blk_data(struct i2c_client *client, u8 command,
> +			       u8 length, const u8 *values)
> +{
> +	int retval = CY_OK;
> +
> +	u8 dataray[CY_MAX_I2C_LEN];
> +	u8 try;
> +	dataray[0] = command;
> +	if (length)
> +		memcpy(&dataray[1], values, length);
> +
> +	try = CY_MAX_TRY;
> +	do {
> +		retval = i2c_master_send(client, dataray, length+1);
> +		mdelay(CY_DLY_DFLT*2);
> +	} while ((retval != length+1) && try--);
> +
> +	return retval;
> +}
> +
> +static int cyttsp_i2c_wr_blk_chunks(struct cyttsp *ts, u8 command,
> +			       u8 length, const u8 *values)
> +{
> +	int retval = CY_OK;
> +	int block = 1;
> +
> +	u8 dataray[CY_MAX_I2C_LEN];
> +
> +	/* first page already includes the bl page offset */
> +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> +		CY_BL_PAGE_SIZE+1, values);
> +	mdelay(10);
> +	values += CY_BL_PAGE_SIZE+1;
> +	length -= CY_BL_PAGE_SIZE+1;
> +
> +	/* rem blocks require bl page offset stuffing */
> +	while (length &&
> +		(block < CY_BL_NUM_PAGES) &&
> +		!(retval < CY_OK)) {
> +		dataray[0] = CY_BL_PAGE_SIZE*block;
> +		memcpy(&dataray[1], values,
> +			length >= CY_BL_PAGE_SIZE ?
> +			CY_BL_PAGE_SIZE : length);
> +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> +			CY_REG_BASE,
> +			length >= CY_BL_PAGE_SIZE ?
> +			CY_BL_PAGE_SIZE + 1 : length+1, dataray);
> +		mdelay(10);
> +		values += CY_BL_PAGE_SIZE;
> +		length = length >= CY_BL_PAGE_SIZE ?
> +			length - CY_BL_PAGE_SIZE : 0;
> +		block++;
> +	}
> +
> +	return retval;
> +}
> +
> +static int cyttsp_bootload_app(struct cyttsp *ts)
> +{
> +	int retval = CY_OK;
> +	int i, tries;
> +	u8 host_reg;
> +
> +	cyttsp_debug("load new firmware \n");
> +	/* reset TTSP Device back to bootloader mode */
> +	host_reg = CY_SOFT_RESET_MODE;
> +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> +		sizeof(host_reg), &host_reg);
> +	/* wait for TTSP Device to complete reset back to bootloader */
> +	mdelay(1000);
> +	cyttsp_putbl(ts, 3, true, true, true);
> +	cyttsp_debug("load file - tver=0x%02X%02X a_id=0x%02X%02X aver=0x%02X%02X\n", \
> +		cyttsp_fw_tts_verh, cyttsp_fw_tts_verl, \
> +		cyttsp_fw_app_idh, cyttsp_fw_app_idl, \
> +		cyttsp_fw_app_verh, cyttsp_fw_app_verl);
> +
> +	/* download new TTSP Application to the Bootloader */
> +	if (!(retval < CY_OK)) {
> +		i = 0;
> +		/* send bootload initiation command */
> +		if (cyttsp_fw[i].Command == CY_BL_INIT_LOAD) {
> +			g_bl_data.bl_file = 0;
> +			g_bl_data.bl_status = 0;
> +			g_bl_data.bl_error = 0;
> +			retval = i2c_smbus_write_i2c_block_data(ts->client,
> +				CY_REG_BASE,
> +				cyttsp_fw[i].Length, cyttsp_fw[i].Block);
> +			/* delay to allow bl to get ready for block writes */
> +			i++;
> +			tries = 0;
> +			cyttsp_debug("wait init f=%02X, s=%02X, e=%02X t=%d\n", \
> +				g_bl_data.bl_file, g_bl_data.bl_status, \
> +				g_bl_data.bl_error, tries);
> +			do {
> +				mdelay(1000);
> +				cyttsp_putbl(ts, 4, true, false, false);
> +			} while (g_bl_data.bl_status != 0x10 &&
> +				g_bl_data.bl_status != 0x11 &&
> +				tries++ < 10);
> +			/* send bootload firmware load blocks */
> +			if (!(retval < CY_OK)) {
> +				while (cyttsp_fw[i].Command == CY_BL_WRITE_BLK) {
> +					retval = cyttsp_i2c_wr_blk_chunks(ts,
> +						CY_REG_BASE,
> +						cyttsp_fw[i].Length,
> +						cyttsp_fw[i].Block);
> +					/* bl requires dly after blocks */
> +					mdelay(100);
> +					cyttsp_debug("BL DNLD Rec=% 3d Len=% 3d Addr=%04X\n", \
> +						cyttsp_fw[i].Record, \
> +						cyttsp_fw[i].Length, \
> +						cyttsp_fw[i].Address);
> +					i++;
> +					if (retval < CY_OK) {
> +						cyttsp_debug("BL fail Rec=%3d retval=%d\n", \
> +							cyttsp_fw[i-1].Record, \
> +							retval);
> +						break;
> +					} else {
> +						/* reset TTSP I2C counter */
> +						retval = cyttsp_i2c_wr_blk_data(ts->client,
> +							CY_REG_BASE,
> +							0, NULL);
> +						mdelay(10);
> +						cyttsp_putbl(ts, 5,
> +							true, false, false);
> +					}
> +				}
> +				if (!(retval < CY_OK)) {
> +					while (i < cyttsp_fw_records) {
> +						retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> +							cyttsp_fw[i].Length,
> +							cyttsp_fw[i].Block);
> +						i++;
> +						tries = 0;
> +						cyttsp_debug("wait init f=%02X, s=%02X, e=%02X t=%d\n", \
> +							g_bl_data.bl_file, \
> +							g_bl_data.bl_status, \
> +							g_bl_data.bl_error, \
> +							tries);
> +						do {
> +							mdelay(1000);
> +							cyttsp_putbl(ts, 6, true, false, false);
> +						} while (g_bl_data.bl_status != 0x10 &&
> +							g_bl_data.bl_status != 0x11 &&
> +							tries++ < 10);
> +						cyttsp_putbl(ts, 7, true, false,
> +							false);
> +						if (retval < CY_OK)
> +							break;
> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	/* reset TTSP Device back to bootloader mode */
> +	host_reg = CY_SOFT_RESET_MODE;
> +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> +		sizeof(host_reg), &host_reg);
> +	/* wait for TTSP Device to complete reset back to bootloader */
> +	mdelay(1000);
> +
> +	/* set arg2 to non-0 to activate */
> +	retval = cyttsp_putbl(ts, 8, true, true, true);
> +
> +	return retval;
> +}
> +#else
> +static int cyttsp_bootload_app(struct cyttsp *ts)
> +{
> +	cyttsp_debug("no-load new firmware \n");
> +	return CY_OK;
> +}
> +#endif /* CY_INCLUDE_LOAD_FILE */
> +
> +
> +static int cyttsp_power_on(struct cyttsp *ts)
> +{
> +	int retval = CY_OK;
> +	u8 host_reg;
> +	int tries;
> +
> +	cyttsp_debug("Power up \n");
> +
> +	/* check if the TTSP device has a bootloader installed */
> +	host_reg = CY_SOFT_RESET_MODE;
> +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> +		sizeof(host_reg), &host_reg);
> +	tries = 0;
> +	do {
> +		mdelay(1000);
> +
> +		/* set arg2 to non-0 to activate */
> +		retval = cyttsp_putbl(ts, 1, true, true, true);
> +		cyttsp_info("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X R=%d\n", \
> +			101, \
> +			g_bl_data.bl_file, g_bl_data.bl_status, \
> +			g_bl_data.bl_error, \
> +			g_bl_data.blver_hi, g_bl_data.blver_lo, \
> +			g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo,
> +			retval);
> +		cyttsp_info("BL%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
> +			102, \
> +			g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
> +			g_bl_data.appid_hi, g_bl_data.appid_lo, \
> +			g_bl_data.appver_hi, g_bl_data.appver_lo);
> +		cyttsp_info("BL%d: c_id=%02X%02X%02X\n", \
> +			103, \
> +			g_bl_data.cid_0, g_bl_data.cid_1, g_bl_data.cid_2);
> +	} while (!(retval < CY_OK) &&
> +		!GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
> +		!(g_bl_data.bl_file == CY_OP_MODE + CY_LOW_PWR_MODE) &&
> +		tries++ < 10);
> +
> +	/* is bootloader missing? */
> +	if (!(retval < CY_OK)) {
> +		cyttsp_xdebug("Ret=%d  Check if bootloader is missing...\n", \
> +			retval);
> +		if (!GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
> +			/* skip all bl and sys info and go to op mode */
> +			if (!(retval < CY_OK)) {
> +				cyttsp_xdebug("Bl is missing (ret=%d)\n", \
> +					retval);
> +				host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
> +				retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> +					sizeof(host_reg), &host_reg);
> +				/* wait for TTSP Device to complete switch to
> +				 * Operational mode */
> +				mdelay(1000);
> +				goto bypass;
> +			}
> +		}
> +	}
> +
> +
> +	/* take TTSP out of bootloader mode; go to TrueTouch operational mode */
> +	if (!(retval < CY_OK)) {
> +		cyttsp_xdebug1("exit bootloader; go operational\n");
> +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> +			CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
> +		tries = 0;
> +		do {
> +			mdelay(1000);
> +			cyttsp_putbl(ts, 4, true, false, false);
> +			cyttsp_info("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X\n", \
> +				104, \
> +				g_bl_data.bl_file, g_bl_data.bl_status, \
> +				g_bl_data.bl_error, \
> +				g_bl_data.blver_hi, g_bl_data.blver_lo, \
> +				g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo);
> +		} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
> +			tries++ < 10);
> +	}
> +
> +
> +
> +	if (!(retval < CY_OK) &&
> +		cyttsp_app_load()) {
> +		mdelay(1000);
> +		if (CY_DIFF(g_bl_data.ttspver_hi, cyttsp_tts_verh())  ||
> +			CY_DIFF(g_bl_data.ttspver_lo, cyttsp_tts_verl())  ||
> +			CY_DIFF(g_bl_data.appid_hi, cyttsp_app_idh())  ||
> +			CY_DIFF(g_bl_data.appid_lo, cyttsp_app_idl())  ||
> +			CY_DIFF(g_bl_data.appver_hi, cyttsp_app_verh())  ||
> +			CY_DIFF(g_bl_data.appver_lo, cyttsp_app_verl())  ||
> +			CY_DIFF(g_bl_data.cid_0, cyttsp_cid_0())  ||
> +			CY_DIFF(g_bl_data.cid_1, cyttsp_cid_1())  ||
> +			CY_DIFF(g_bl_data.cid_2, cyttsp_cid_2())  ||
> +			cyttsp_force_fw_load()) {
> +			cyttsp_debug("blttsp=0x%02X%02X flttsp=0x%02X%02X force=%d\n", \
> +				g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
> +				cyttsp_tts_verh(), cyttsp_tts_verl(), \
> +				cyttsp_force_fw_load());
> +			cyttsp_debug("blappid=0x%02X%02X flappid=0x%02X%02X\n", \
> +				g_bl_data.appid_hi, g_bl_data.appid_lo, \
> +				cyttsp_app_idh(), cyttsp_app_idl());
> +			cyttsp_debug("blappver=0x%02X%02X flappver=0x%02X%02X\n", \
> +				g_bl_data.appver_hi, g_bl_data.appver_lo, \
> +				cyttsp_app_verh(), cyttsp_app_verl());
> +			cyttsp_debug("blcid=0x%02X%02X%02X flcid=0x%02X%02X%02X\n", \
> +				g_bl_data.cid_0, \
> +				g_bl_data.cid_1, \
> +				g_bl_data.cid_2, \
> +				cyttsp_cid_0(), \
> +				cyttsp_cid_1(), \
> +				cyttsp_cid_2());
> +			/* enter bootloader to load new app into TTSP Device */
> +			retval = cyttsp_bootload_app(ts);
> +			/* take TTSP device out of bootloader mode;
> +			 * switch back to TrueTouch operational mode */
> +			if (!(retval < CY_OK)) {
> +				retval = i2c_smbus_write_i2c_block_data(ts->client,
> +					CY_REG_BASE,
> +					sizeof(bl_cmd), bl_cmd);
> +				/* wait for TTSP Device to complete
> +				 * switch to Operational mode */
> +				mdelay(1000);
> +			}
> +		}
> +	}
> +
> +bypass:
> +	/* switch to System Information mode to read versions
> +	 * and set interval registers */
> +	if (!(retval < CY_OK)) {
> +		cyttsp_debug("switch to sysinfo mode \n");
> +		host_reg = CY_SYSINFO_MODE;
> +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> +			CY_REG_BASE, sizeof(host_reg), &host_reg);
> +		/* wait for TTSP Device to complete switch to SysInfo mode */
> +		mdelay(1000);
> +		if (!(retval < CY_OK)) {
> +			retval = i2c_smbus_read_i2c_block_data(ts->client,
> +				CY_REG_BASE,
> +				sizeof(struct cyttsp_sysinfo_data_t),
> +				(u8 *)&g_sysinfo_data);
> +			cyttsp_debug("SI2: hst_mode=0x%02X mfg_cmd=0x%02X mfg_stat=0x%02X\n", \
> +				g_sysinfo_data.hst_mode, \
> +				g_sysinfo_data.mfg_cmd, \
> +				g_sysinfo_data.mfg_stat);
> +			cyttsp_debug("SI2: bl_ver=0x%02X%02X\n", \
> +				g_sysinfo_data.bl_verh, \
> +				g_sysinfo_data.bl_verl);
> +			cyttsp_debug("SI2: sysinfo act_int=0x%02X tch_tmout=0x%02X lp_int=0x%02X\n", \
> +				g_sysinfo_data.act_intrvl, \
> +				g_sysinfo_data.tch_tmout, \
> +				g_sysinfo_data.lp_intrvl);
> +			cyttsp_info("SI%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
> +				102, \
> +				g_sysinfo_data.tts_verh, \
> +				g_sysinfo_data.tts_verl, \
> +				g_sysinfo_data.app_idh, \
> +				g_sysinfo_data.app_idl, \
> +				g_sysinfo_data.app_verh, \
> +				g_sysinfo_data.app_verl);
> +			cyttsp_info("SI%d: c_id=%02X%02X%02X\n", \
> +				103, \
> +				g_sysinfo_data.cid[0], \
> +				g_sysinfo_data.cid[1], \
> +				g_sysinfo_data.cid[2]);
> +			if (!(retval < CY_OK) &&
> +				(CY_DIFF(ts->platform_data->act_intrvl,
> +					CY_ACT_INTRVL_DFLT)  ||
> +				CY_DIFF(ts->platform_data->tch_tmout,
> +					CY_TCH_TMOUT_DFLT) ||
> +				CY_DIFF(ts->platform_data->lp_intrvl,
> +					CY_LP_INTRVL_DFLT))) {
> +				if (!(retval < CY_OK)) {
> +					u8 intrvl_ray[sizeof(ts->platform_data->act_intrvl) +
> +						sizeof(ts->platform_data->tch_tmout) +
> +						sizeof(ts->platform_data->lp_intrvl)];
> +					u8 i = 0;
> +
> +					intrvl_ray[i++] =
> +						ts->platform_data->act_intrvl;
> +					intrvl_ray[i++] =
> +						ts->platform_data->tch_tmout;
> +					intrvl_ray[i++] =
> +						ts->platform_data->lp_intrvl;
> +
> +					cyttsp_debug("SI2: platinfo act_intrvl=0x%02X tch_tmout=0x%02X lp_intrvl=0x%02X\n", \
> +						ts->platform_data->act_intrvl, \
> +						ts->platform_data->tch_tmout, \
> +						ts->platform_data->lp_intrvl);
> +					/* set intrvl registers */
> +					retval = i2c_smbus_write_i2c_block_data(
> +						ts->client,
> +						CY_REG_ACT_INTRVL,
> +						sizeof(intrvl_ray), intrvl_ray);
> +					mdelay(CY_DLY_SYSINFO);
> +				}
> +			}
> +		}
> +		/* switch back to Operational mode */
> +		cyttsp_debug("switch back to operational mode \n");
> +		if (!(retval < CY_OK)) {
> +			host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
> +			retval = i2c_smbus_write_i2c_block_data(ts->client,
> +				CY_REG_BASE,
> +				sizeof(host_reg), &host_reg);
> +			/* wait for TTSP Device to complete
> +			 * switch to Operational mode */
> +			mdelay(1000);
> +		}
> +	}
> +	/* init gesture setup;
> +	 * this is required even if not using gestures
> +	 * in order to set the active distance */
> +	if (!(retval < CY_OK)) {
> +		u8 gesture_setup;
> +		cyttsp_debug("init gesture setup \n");
> +		gesture_setup = ts->platform_data->gest_set;
> +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> +			CY_REG_GEST_SET,
> +			sizeof(gesture_setup), &gesture_setup);
> +		mdelay(CY_DLY_DFLT);
> +	}
> +
> +	if (!(retval < CY_OK))
> +		ts->platform_data->power_state = CY_ACTIVE_STATE;
> +	else
> +		ts->platform_data->power_state = CY_IDLE_STATE;
> +
> +	cyttsp_debug("Retval=%d Power state is %s\n", \
> +		retval, \
> +		ts->platform_data->power_state == CY_ACTIVE_STATE ? \
> +		 "ACTIVE" : "IDLE");

Whole function looks scary and hard to understand. Is it possible to break it into the smaller
functionality so that it becomes easy to understand.

> +
> +	return retval;
> +}
> +
> +/* cyttsp_initialize: Driver Initialization. This function takes
> + * care of the following tasks:
> + * 1. Create and register an input device with input layer
> + * 2. Take CYTTSP device out of bootloader mode; go operational
> + * 3. Start any timers/Work queues.  */
> +static int cyttsp_initialize(struct i2c_client *client, struct cyttsp *ts)
> +{
> +	struct input_dev *input_device;
> +	int error = 0;
> +	int retval = CY_OK;
> +	u8 id;
> +
> +	/* Create the input device and register it. */
> +	input_device = input_allocate_device();
> +	if (!input_device) {
> +		error = -ENOMEM;
> +		cyttsp_xdebug1("err input allocate device\n");
> +		goto error_free_device;
> +	}
> +
> +	if (!client) {
> +		error = ~ENODEV;
> +		cyttsp_xdebug1("err client is Null\n");
> +		goto error_free_device;
> +	}

Why you are checking !client here?

> +
> +	if (!ts) {
> +		error = ~ENODEV;

~? It should be -ENODEV, right?

> +		cyttsp_xdebug1("err context is Null\n");
> +		goto error_free_device;
> +	}
> +
> +	ts->input = input_device;
> +	input_device->name = CY_I2C_NAME;
> +	input_device->phys = ts->phys;
> +	input_device->dev.parent = &client->dev;
> +
> +	/* init the touch structures */
> +	ts->num_prv_st_tch = CY_NTCH;
> +	for (id = 0; id < CY_NUM_TRK_ID; id++) {
> +		ts->act_trk[id] = CY_NTCH;
> +		ts->prv_mt_pos[id][CY_XPOS] = 0;
> +		ts->prv_mt_pos[id][CY_YPOS] = 0;
> +	}
> +
> +	for (id = 0; id < CY_NUM_MT_TCH_ID; id++)
> +		ts->prv_mt_tch[id] = CY_IGNR_TCH;
> +
> +	for (id = 0; id < CY_NUM_ST_TCH_ID; id++)
> +		ts->prv_st_tch[id] = CY_IGNR_TCH;
> +
> +	set_bit(EV_SYN, input_device->evbit);
> +	set_bit(EV_KEY, input_device->evbit);
> +	set_bit(EV_ABS, input_device->evbit);
> +	set_bit(BTN_TOUCH, input_device->keybit);
> +	set_bit(BTN_2, input_device->keybit);

You need not use atomic versions. Please use __set_bit.

> +	if (ts->platform_data->use_gestures)
> +		set_bit(BTN_3, input_device->keybit);
> +
> +	input_set_abs_params(input_device,
> +		ABS_X, 0, ts->platform_data->maxx, 0, 0);
> +	input_set_abs_params(input_device,
> +		ABS_Y, 0, ts->platform_data->maxy, 0, 0);
> +	input_set_abs_params(input_device,
> +		ABS_TOOL_WIDTH, 0, CY_LARGE_TOOL_WIDTH, 0 , 0);
> +	input_set_abs_params(input_device,
> +		ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
> +	input_set_abs_params(input_device,
> +		ABS_HAT0X, 0, ts->platform_data->maxx, 0, 0);
> +	input_set_abs_params(input_device,
> +		ABS_HAT0Y, 0, ts->platform_data->maxy, 0, 0);

Why you are using HATxx? MT should be able to satisfy all the requirements.

> +	if (ts->platform_data->use_gestures) {
> +		input_set_abs_params(input_device,
> +			ABS_HAT1X, 0, CY_MAXZ, 0, 0);
> +		input_set_abs_params(input_device,
> +			ABS_HAT1Y, 0, CY_MAXZ, 0, 0);
> +	}
> +	if (ts->platform_data->use_mt) {
> +		input_set_abs_params(input_device,
> +			ABS_MT_POSITION_X, 0, ts->platform_data->maxx, 0, 0);
> +		input_set_abs_params(input_device,
> +			ABS_MT_POSITION_Y, 0, ts->platform_data->maxy, 0, 0);
> +		input_set_abs_params(input_device,
> +			ABS_MT_TOUCH_MAJOR, 0, CY_MAXZ, 0, 0);
> +		input_set_abs_params(input_device,
> +			ABS_MT_WIDTH_MAJOR, 0, CY_LARGE_TOOL_WIDTH, 0, 0);
> +		if (ts->platform_data->use_trk_id) {
> +			input_set_abs_params(input_device,
> +				ABS_MT_TRACKING_ID, 0, CY_NUM_TRK_ID, 0, 0);
> +		}
> +	}
> +
> +	/* set dummy key to make driver work with virtual keys */
> +	input_set_capability(input_device, EV_KEY, KEY_PROG1);

What is virtual keys and how they are supported? 

> +
> +	cyttsp_info("%s: Register input device\n", CY_I2C_NAME);
> +	error = input_register_device(input_device);
> +	if (error) {
> +		cyttsp_alert("%s: Failed to register input device\n", \
> +			CY_I2C_NAME);
> +		retval = error;
> +		goto error_free_device;
> +	}
> +
> +	/* Prepare our worker structure prior to setting up the timer/ISR */
> +	INIT_WORK(&ts->work, cyttsp_xy_worker);
> +
> +	/* Power on the chip and make sure that I/Os are set as specified
> +	 * in the platform */
> +	if (ts->platform_data->init)
> +		retval = ts->platform_data->init(client);
> +
> +	if (!(retval < CY_OK))
> +		retval = cyttsp_power_on(ts);
> +
> +	if (retval < 0)
> +		goto error_free_device;

Wrong. 

if (!rc) {
     rc = power_on(ts);
     if (!rc) {
         rc = -Exxx;
         goto error_path;
     }
}

> +
> +	/* Timer or Interrupt setup */
> +	if (ts->client->irq == 0) {
> +		cyttsp_info("Setting up timer\n");
> +		setup_timer(&ts->timer, cyttsp_timer, (unsigned long) ts);
> +		mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);

Please support only one mode in the driver. Most of the time polling mode is used
only during early development phase when the IRQs doesn't work, but we don't want to carry
this code here. 

Please remove polling mode code.

> +	} else {
> +		cyttsp_info("Setting up interrupt\n");
> +		/* request_irq() will also call enable_irq() */
> +		error = request_irq(client->irq, cyttsp_irq,
> +			IRQF_TRIGGER_FALLING,
> +			client->dev.driver->name, ts);

Please use request_threaded_irq(...) with IRQF_ONESHOT flag.

> +		if (error) {
> +			cyttsp_alert("error: could not request irq\n");
> +			retval = error;
> +			goto error_free_irq;
> +		}
> +	}
> +
> +	irq_cnt = 0;
> +	irq_cnt_total = 0;
> +	irq_err_cnt = 0;
> +
> +	atomic_set(&ts->irq_enabled, 1);
> +	retval = device_create_file(&ts->client->dev, &dev_attr_irq_enable);
> +	if (retval < CY_OK) {
> +		cyttsp_alert("File device creation failed: %d\n", retval);
> +		retval = -ENODEV;
> +		goto error_free_irq;
> +	}
> +
> +	cyttsp_info("%s: Successful registration\n", CY_I2C_NAME);
> +	goto success;
> +
> +error_free_irq:
> +	cyttsp_alert("Error: Failed to register IRQ handler\n");
> +	free_irq(client->irq, ts);
> +
> +error_free_device:
> +	if (input_device)
> +		input_free_device(input_device);
> +
> +success:
> +	return retval;
> +}
> +
> +/* I2C driver probe function */
> +static int __devinit cyttsp_probe(struct i2c_client *client,
> +			const struct i2c_device_id *id)
> +{
> +	struct cyttsp *ts;
> +	int error;
> +	int retval = CY_OK;

Please don't define your own error return codes. Use appropriate one
from the kernel like say -EINVAL etc.,

> +
> +	cyttsp_info("Start Probe 1.2\n");

Please remove such debug statements. They are of no use.

I don't see call to i2c_check_functionality(...)

> +
> +	/* allocate and clear memory */
> +	ts = kzalloc(sizeof(struct cyttsp), GFP_KERNEL);
> +	if (ts == NULL) {
> +		cyttsp_xdebug1("err kzalloc for cyttsp\n");

Please use dev_dbg or pr_debug provided by kernel only. This comment applies to whole driver.
We don't need driver specific macros please.

> +		retval = -ENOMEM;
> +	}
> +
> +	if (!(retval < CY_OK)) {
> +		/* register driver_data */
> +		ts->client = client;
> +		ts->platform_data = client->dev.platform_data;
> +		i2c_set_clientdata(client, ts);
> +
> +		error = cyttsp_initialize(client, ts);
> +		if (error) {
> +			cyttsp_xdebug1("err cyttsp_initialize\n");
> +			if (ts != NULL) {
> +				/* deallocate memory */
> +				kfree(ts);
> +			}
> +/*
> +			i2c_del_driver(&cyttsp_driver);
> +*/

Do you need this commented out code?

> +			retval = -ENODEV;
> +		} else
> +			cyttsp_openlog();
> +	}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	if (!(retval < CY_OK)) {
> +		ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
> +		ts->early_suspend.suspend = cyttsp_early_suspend;
> +		ts->early_suspend.resume = cyttsp_late_resume;
> +		register_early_suspend(&ts->early_suspend);
> +	}
> +#endif /* CONFIG_HAS_EARLYSUSPEND */

As mentioned above I want all the early suspend code to be removed. Explore RunTime PM framework of the kernel.

> +
> +	cyttsp_info("Start Probe %s\n", \
> +		(retval < CY_OK) ? "FAIL" : "PASS");
> +
> +	return retval;
> +}
> +
> +/* Function to manage power-on resume */
> +static int cyttsp_resume(struct i2c_client *client)
> +{
> +	struct cyttsp *ts;
> +	int retval = CY_OK;
> +
> +	cyttsp_debug("Wake Up\n");
> +	ts = (struct cyttsp *) i2c_get_clientdata(client);

No need of casting. 

> +
> +	/* re-enable the interrupt prior to wake device */
> +	if (ts->client->irq)
> +		enable_irq(ts->client->irq);
> +
> +	if (ts->platform_data->use_sleep &&
> +		(ts->platform_data->power_state != CY_ACTIVE_STATE)) {
> +		if (ts->platform_data->resume)
> +			retval = ts->platform_data->resume(client);
> +		if (!(retval < CY_OK)) {
> +			retval = i2c_smbus_read_i2c_block_data(ts->client,
> +				CY_REG_BASE,
> +				sizeof(struct cyttsp_bootloader_data_t),
> +				(u8 *)&g_bl_data);
> +			if (!(retval < CY_OK) &&
> +				GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
> +				u8 tries;
> +				retval = i2c_smbus_write_i2c_block_data(
> +					ts->client,
> +					CY_REG_BASE,
> +					sizeof(bl_cmd), bl_cmd);
> +				/* switch back to operational mode */
> +				tries = 0;
> +				mdelay(10);
> +				while (GET_BOOTLOADERMODE(g_bl_data.bl_status)
> +					&& tries++ < 10) {
> +					mdelay(100);

Do you really need to use mdelay(...) in the resume path? Is there any way you could use msleep(..)
or say no delay at all.

> +					cyttsp_putbl(ts, 16,
> +						false, false, false);
> +				}
> +			}
> +		}
> +	}
> +
> +	if (!(retval < CY_OK) &&
> +		(GET_HSTMODE(g_bl_data.bl_file) == CY_OK)) {
> +		ts->platform_data->power_state = CY_ACTIVE_STATE;
> +
> +		/* re-enable the timer after resuming */
> +		if (ts->client->irq == 0)
> +			mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
> +	} else
> +		retval = -ENODEV;
> +
> +	cyttsp_debug("Wake Up %s\n", \
> +		(retval < CY_OK) ? "FAIL" : "PASS");
> +
> +	return retval;
> +}
> +
> +
> +/* Function to manage low power suspend */
> +static int cyttsp_suspend(struct i2c_client *client, pm_message_t message)

Please put #ifdef CONFIG_PM around suspend/resume functions.

> +{
> +	struct cyttsp *ts;
> +	u8 sleep_mode = CY_OK;
> +	int retval = CY_OK;
> +
> +	cyttsp_debug("Enter Sleep\n");
> +	ts = (struct cyttsp *) i2c_get_clientdata(client);

Casting from void * is not required. Please remove.

> +
> +	/* disable worker */
> +	if (ts->client->irq == 0)
> +		del_timer(&ts->timer);
> +	else
> +		disable_irq_nosync(ts->client->irq);
> +	retval = cancel_work_sync(&ts->work);
> +
> +	if (retval)
> +		enable_irq(ts->client->irq);
> +
> +	if (!(retval < CY_OK)) {
> +		if (ts->platform_data->use_sleep &&
> +			(ts->platform_data->power_state == CY_ACTIVE_STATE)) {
> +			if (ts->platform_data->use_sleep & CY_USE_DEEP_SLEEP_SEL)
> +				sleep_mode = CY_DEEP_SLEEP_MODE;
> +			else
> +				sleep_mode = CY_LOW_PWR_MODE;
> +
> +			retval = i2c_smbus_write_i2c_block_data(ts->client,
> +				CY_REG_BASE,
> +				sizeof(sleep_mode), &sleep_mode);
> +		}
> +	}
> +
> +	if (!(retval < CY_OK)) {
> +		if (sleep_mode == CY_DEEP_SLEEP_MODE)
> +			ts->platform_data->power_state = CY_SLEEP_STATE;
> +		else if (sleep_mode == CY_LOW_PWR_MODE)
> +			ts->platform_data->power_state = CY_LOW_PWR_STATE;
> +	}
> +
> +	cyttsp_debug("Sleep Power state is %s\n", \
> +		(ts->platform_data->power_state == CY_ACTIVE_STATE) ? \
> +		"ACTIVE" : \
> +		((ts->platform_data->power_state == CY_SLEEP_STATE) ? \
> +		"SLEEP" : "LOW POWER"));
> +
> +	return retval;
> +}
> +
> +/* registered in driver struct */
> +static int __devexit cyttsp_remove(struct i2c_client *client)
> +{
> +	struct cyttsp *ts;
> +	int err;
> +
> +	cyttsp_alert("Unregister\n");
> +
> +	/* clientdata registered on probe */
> +	ts = i2c_get_clientdata(client);
> +	device_remove_file(&ts->client->dev, &dev_attr_irq_enable);
> +
> +	/* Start cleaning up by removing any delayed work and the timer */
> +	if (cancel_delayed_work((struct delayed_work *)&ts->work) < CY_OK)
> +		cyttsp_alert("error: could not remove work from workqueue\n");
> +
> +	/* free up timer or irq */
> +	if (ts->client->irq == 0) {
> +		err = del_timer(&ts->timer);
> +		if (err < CY_OK)
> +			cyttsp_alert("error: failed to delete timer\n");
> +	} else
> +		free_irq(client->irq, ts);
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +	unregister_early_suspend(&ts->early_suspend);
> +#endif /* CONFIG_HAS_EARLYSUSPEND */
> +
> +	/* housekeeping */
> +	if (ts != NULL)
> +		kfree(ts);
> +
> +	cyttsp_alert("Leaving\n");

I don't removal of input_dev structures.

> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_HAS_EARLYSUSPEND
> +static void cyttsp_early_suspend(struct early_suspend *handler)
> +{
> +	struct cyttsp *ts;
> +
> +	ts = container_of(handler, struct cyttsp, early_suspend);
> +	cyttsp_suspend(ts->client, PMSG_SUSPEND);
> +}
> +
> +static void cyttsp_late_resume(struct early_suspend *handler)
> +{
> +	struct cyttsp *ts;
> +
> +	ts = container_of(handler, struct cyttsp, early_suspend);
> +	cyttsp_resume(ts->client);
> +}
> +#endif  /* CONFIG_HAS_EARLYSUSPEND */
> +
> +static int cyttsp_init(void)
> +{

__init 

> +	int ret;
> +
> +	cyttsp_info("Cypress TrueTouch(R) Standard Product\n");
> +	cyttsp_info("I2C Touchscreen Driver (Built %s @ %s)\n", \
> +		__DATE__, __TIME__);
> +
> +	cyttsp_ts_wq = create_singlethread_workqueue("cyttsp_ts_wq");
> +	if (cyttsp_ts_wq == NULL) {
> +		cyttsp_debug("No memory for cyttsp_ts_wq\n");
> +		return -ENOMEM;
> +	}
> +
> +	ret = i2c_add_driver(&cyttsp_driver);
> +
> +	return ret;
> +}
> +
> +static void cyttsp_exit(void)
> +{

__exit 

> +	if (cyttsp_ts_wq)
> +		destroy_workqueue(cyttsp_ts_wq);
> +	return i2c_del_driver(&cyttsp_driver);
> +}
> +
> +module_init(cyttsp_init);
> +module_exit(cyttsp_exit);
> +
> diff --git a/include/linux/cyttsp.h b/include/linux/cyttsp.h
> new file mode 100644
> index 0000000..2ab1a5c
> --- /dev/null
> +++ b/include/linux/cyttsp.h
> @@ -0,0 +1,649 @@
> +/* Header file for:
> + * Cypress TrueTouch(TM) Standard Product touchscreen drivers.
> + * include/linux/cyttsp.h

No file paths please.

> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Cypress reserves the right to make changes without further notice
> + * to the materials described herein. Cypress does not assume any
> + * liability arising out of the application described herein.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com
> + *
> + */
> +
> +
> +#ifndef __CYTTSP_H__
> +#define __CYTTSP_H__
> +
> +#include <linux/input.h>
> +#include <linux/timer.h>
> +#include <linux/workqueue.h>
> +#include <linux/kernel.h>
> +#include <linux/delay.h>
> +
> +#define CYPRESS_TTSP_NAME	"cyttsp"
> +#define CY_I2C_NAME		"cyttsp-i2c"
> +#define CY_SPI_NAME		"cyttsp-spi"

I don't think that driver could be easily converted to fit with "spi",
as I see i2c calls all over.

> +
> +#ifdef CY_DECLARE_GLOBALS
> +	uint32_t cyttsp_tsdebug;
> +	module_param_named(tsdebug, cyttsp_tsdebug, uint, 0664);
> +	uint32_t cyttsp_tsxdebug;
> +	module_param_named(tsxdebug, cyttsp_tsxdebug, uint, 0664);
> +
> +	uint32_t cyttsp_disable_touch;
> +	module_param_named(disable_touch, cyttsp_disable_touch, uint, 0664);
> +#else
> +	extern uint32_t cyttsp_tsdebug;
> +	extern uint32_t cyttsp_tsxdebug;
> +	extern uint32_t cyttsp_disable_touch;
> +#endif
> +
> +
> +
> +/******************************************************************************
> + * Global Control, Used to control the behavior of the driver
> + */
> +
> +/* defines for Gen2 (Txx2xx); Gen3 (Txx3xx)
> + * use these defines to set cyttsp_platform_data.gen in board config file
> + */
> +#define CY_GEN2		2
> +#define CY_GEN3		3
> +
> +/* define for using I2C driver
> + */
> +#define CY_USE_I2C_DRIVER
> +
> +/* defines for using SPI driver */
> +/*
> +#define CY_USE_SPI_DRIVER
> + */
> +#define CY_SPI_DFLT_SPEED_HZ		1000000
> +#define CY_SPI_MAX_SPEED_HZ		4000000
> +#define CY_SPI_SPEED_HZ			CY_SPI_DFLT_SPEED_HZ
> +#define CY_SPI_BITS_PER_WORD		8
> +#define CY_SPI_DAV			139	/* set correct gpio id */
> +#define CY_SPI_BUFSIZE			512


No need of these #defines unless we see driver for SPI.

> +
> +
> +/* define for inclusion of TTSP App Update Load File
> + * use this define if update to the TTSP Device is desired
> + */
> +/*
> +#define CY_INCLUDE_LOAD_FILE
> +*/
> +
> +/* define if force new load file for bootloader load */
> +/*
> +#define CY_FORCE_FW_UPDATE
> +*/
> +
> +/* undef for production use */
> +/*
> + */
> +#define CY_USE_DEBUG

As indicated please use kernel dev_dbg/dev_xxx and pr_debug/pr_xxx friends.

> +
> +/* undef for irq use; use this define in the board configuration file */
> +/*
> +#define CY_USE_TIMER
> + */

As indicated above polling mode should be removed.

> +
> +/* undef to allow use of extra debug capability */
> +/*
> +#define CY_ALLOW_EXTRA_DEBUG
> +*/
> +
> +/* undef to remove additional debug prints */
> +/*
> +#define CY_USE_EXTRA_DEBUG
> +*/
> +
> +/* undef to remove additional debug prints */
> +/*
> +#define CY_USE_EXTRA_DEBUG1
> + */
> +
> +/* undef to use operational touch timer jiffies; else use test jiffies */
> +/*
> +#define CY_USE_TIMER_DEBUG
> + */
> +
> +/* define to use canned test data */
> +/*
> +#define CY_USE_TEST_DATA
> + */
> +
> +/* define to activate power management */
> +/*
> +#define CY_USE_LOW_POWER
> + */

Please see if you can use RunTime PM apis for LPM.

> +
> +/* define if wake on i2c addr is activated */
> +/*
> +#define CY_USE_DEEP_SLEEP
> + */
> +
> +/* define if gesture signaling is used
> + * and which gesture groups to use
> + */
> +/*
> +#define CY_USE_GEST
> +#define CY_USE_GEST_GRP1
> +#define CY_USE_GEST_GRP2
> +#define CY_USE_GEST_GRP3
> +#define CY_USE_GEST_GRP4
> + */
> +/* Active distance in pixels for a gesture to be reported
> + * if set to 0, then all gesture movements are reported
> + */
> +#define CY_ACT_DIST_DFLT	8
> +#define CY_ACT_DIST			CY_ACT_DIST_DFLT
> +
> +/* define if MT signals are desired */
> +/*
> +*/
> +#define CY_USE_MT_SIGNALS
> +
> +/* define if MT tracking id signals are used */
> +/*
> +#define CY_USE_MT_TRACK_ID
> + */
> +
> +/* define if ST signals are required */
> +/*
> +#define CY_USE_ST_SIGNALS
> +*/
> +
> +/* define to send handshake to device */
> +/*
> +#define CY_USE_HNDSHK
> +*/
> +
> +/* define if log all raw motion signals to a sysfs file */
> +/*
> +#define CY_LOG_TO_FILE
> +*/
> +
> +
> +/* End of the Global Control section
> + ******************************************************************************
> + */
> +#define CY_DIFF(m, n)		((m) != (n))
> +
> +#ifdef CY_LOG_TO_FILE
> +	#define cyttsp_openlog()	/* use sysfs */
> +#else
> +	#define cyttsp_openlog()
> +#endif /* CY_LOG_TO_FILE */
> +
> +/* see kernel.h for pr_xxx def'ns */
> +#define cyttsp_info(f, a...)		pr_info("%s:" f,  __func__ , ## a)
> +#define cyttsp_error(f, a...)		pr_err("%s:" f,  __func__ , ## a)
> +#define cyttsp_alert(f, a...)		pr_alert("%s:" f,  __func__ , ## a)
> +
> +#ifdef CY_USE_DEBUG
> +	#define cyttsp_debug(f, a...)	pr_alert("%s:" f,  __func__ , ## a)
> +#else
> +	#define cyttsp_debug(f, a...)	{if (cyttsp_tsdebug) \
> +					pr_alert("%s:" f,  __func__ , ## a); }
> +#endif /* CY_USE_DEBUG */
> +
> +#ifdef CY_ALLOW_EXTRA_DEBUG
> +#ifdef CY_USE_EXTRA_DEBUG
> +	#define cyttsp_xdebug(f, a...)	pr_alert("%s:" f,  __func__ , ## a)
> +#else
> +	#define cyttsp_xdebug(f, a...)	{if (cyttsp_tsxdebug) \
> +					pr_alert("%s:" f,  __func__ , ## a); }
> +#endif /* CY_USE_EXTRA_DEBUG */
> +
> +#ifdef CY_USE_EXTRA_DEBUG1
> +	#define cyttsp_xdebug1(f, a...)	pr_alert("%s:" f,  __func__ , ## a)
> +#else
> +	#define cyttsp_xdebug1(f, a...)
> +#endif /* CY_USE_EXTRA_DEBUG1 */
> +#else
> +	#define cyttsp_xdebug(f, a...)
> +	#define cyttsp_xdebug1(f, a...)
> +#endif /* CY_ALLOW_EXTRA_DEBUG */

Please remove customized debugs.

> +
> +#ifdef CY_USE_TIMER_DEBUG
> +	#define	TOUCHSCREEN_TIMEOUT	(msecs_to_jiffies(1000))
> +#else
> +	#define	TOUCHSCREEN_TIMEOUT	(msecs_to_jiffies(28))
> +#endif
> +



> +/* reduce extra signals in MT only build
> + * be careful not to lose backward compatibility for pre-MT apps
> + */
> +#ifdef CY_USE_ST_SIGNALS
> +	#define CY_USE_ST	1
> +#else
> +	#define CY_USE_ST	0
> +#endif /* CY_USE_ST_SIGNALS */
> +
> +/* rely on kernel input.h to define Multi-Touch capability */
> +/* if input.h defines the Multi-Touch signals, then use MT */
> +#if defined(ABS_MT_TOUCH_MAJOR) && defined(CY_USE_MT_SIGNALS)
> +	#define CY_USE_MT	1
> +	#define CY_MT_SYNC(input)	input_mt_sync(input)
> +#else

I don't think we need such hacks, as latest kernel supports MT.

> +	#define CY_USE_MT	0
> +	#define CY_MT_SYNC(input)
> +	/* the following includes are provided to ensure a compile;
> +	 * the code that compiles with these defines will not be executed if
> +	 * the CY_USE_MT is properly used in the platform structure init
> +	 */
> +	#ifndef ABS_MT_TOUCH_MAJOR
> +	#define ABS_MT_TOUCH_MAJOR	0x30	/* touching ellipse */
> +	#define ABS_MT_TOUCH_MINOR	0x31	/* (omit if circular) */
> +	#define ABS_MT_WIDTH_MAJOR	0x32	/* approaching ellipse */
> +	#define ABS_MT_WIDTH_MINOR	0x33	/* (omit if circular) */
> +	#define ABS_MT_ORIENTATION	0x34	/* Ellipse orientation */
> +	#define ABS_MT_POSITION_X	0x35	/* Center X ellipse position */
> +	#define ABS_MT_POSITION_Y	0x36	/* Center Y ellipse position */
> +	#define ABS_MT_TOOL_TYPE	0x37	/* Type of touching device */
> +	#define ABS_MT_BLOB_ID		0x38	/* Group set of pkts as blob */
> +	#endif /* ABS_MT_TOUCH_MAJOR */
> +#endif /* ABS_MT_TOUCH_MAJOR and CY_USE_MT_SIGNALS */
> +#if defined(ABS_MT_TRACKING_ID)  && defined(CY_USE_MT_TRACK_ID)
> +	#define CY_USE_TRACKING_ID	1
> +#else
> +	#define CY_USE_TRACKING_ID	0
> +/* define only if not defined already by system;
> + * value based on linux kernel 2.6.30.10
> + */
> +#ifndef ABS_MT_TRACKING_ID
> +	#define ABS_MT_TRACKING_ID	(ABS_MT_BLOB_ID+1)
> +#endif
> +#endif /* ABS_MT_TRACKING_ID */
> +
> +#ifdef CY_USE_DEEP_SLEEP
> +	#define CY_USE_DEEP_SLEEP_SEL	0x80
> +#else
> +	#define CY_USE_DEEP_SLEEP_SEL	0x00
> +#endif
> +#ifdef CY_USE_LOW_POWER
> +	#define CY_USE_SLEEP	(CY_USE_DEEP_SLEEP_SEL | 0x01)
> +#else
> +	#define CY_USE_SLEEP	0x00
> +#endif /* CY_USE_LOW_POWER */
> +
> +#ifdef CY_USE_TEST_DATA
> +	#define cyttsp_testdat(ray1, ray2, sizeofray) \
> +		{ \
> +			int i; \
> +			u8 *up1 = (u8 *)ray1; \
> +			u8 *up2 = (u8 *)ray2; \
> +			for (i = 0; i < sizeofray; i++) { \
> +				up1[i] = up2[i]; \
> +			} \
> +		}
> +#else
> +	#define cyttsp_testdat(xy, test_xy, sizeofray)
> +#endif /* CY_USE_TEST_DATA */
> +
> +/* helper macros */
> +#define GET_NUM_TOUCHES(x)		((x) & 0x0F)
> +#define GET_TOUCH1_ID(x)		(((x) & 0xF0) >> 4)
> +#define GET_TOUCH2_ID(x)		((x) & 0x0F)
> +#define GET_TOUCH3_ID(x)		(((x) & 0xF0) >> 4)
> +#define GET_TOUCH4_ID(x)		((x) & 0x0F)
> +#define IS_LARGE_AREA(x)		(((x) & 0x10) >> 4)
> +#define FLIP_DATA_FLAG			0x01
> +#define REVERSE_X_FLAG			0x02
> +#define REVERSE_Y_FLAG			0x04
> +#define FLIP_DATA(flags)		((flags) & FLIP_DATA_FLAG)
> +#define REVERSE_X(flags)		((flags) & REVERSE_X_FLAG)
> +#define REVERSE_Y(flags)		((flags) & REVERSE_Y_FLAG)
> +#define FLIP_XY(x, y)			{ \
> +						u16 tmp; \
> +						tmp = (x); \
> +						(x) = (y); \
> +						(y) = tmp; \
> +					}
> +#define INVERT_X(x, xmax)		((xmax) - (x))
> +#define INVERT_Y(y, ymax)		((ymax) - (y))
> +#define SET_HSTMODE(reg, mode)		((reg) & (mode))
> +#define GET_HSTMODE(reg)		((reg & 0x70) >> 4)
> +#define GET_BOOTLOADERMODE(reg)		((reg & 0x10) >> 4)
> +
> +/* constant definitions */
> +/* maximum number of concurrent ST track IDs */
> +#define CY_NUM_ST_TCH_ID		2
> +
> +/* maximum number of concurrent MT track IDs */
> +#define CY_NUM_MT_TCH_ID		4
> +
> +/* maximum number of track IDs */
> +#define CY_NUM_TRK_ID			16
> +
> +#define CY_NTCH				0	/* no touch (lift off) */
> +#define CY_TCH				1	/* active touch (touchdown) */
> +#define CY_ST_FNGR1_IDX			0
> +#define CY_ST_FNGR2_IDX			1
> +#define CY_MT_TCH1_IDX			0
> +#define CY_MT_TCH2_IDX			1
> +#define CY_MT_TCH3_IDX			2
> +#define CY_MT_TCH4_IDX			3
> +#define CY_XPOS				0
> +#define CY_YPOS				1
> +#define CY_IGNR_TCH			(-1)
> +#define CY_SMALL_TOOL_WIDTH		10
> +#define CY_LARGE_TOOL_WIDTH		255
> +#define CY_REG_BASE			0x00
> +#define CY_REG_GEST_SET			0x1E
> +#define CY_REG_ACT_INTRVL		0x1D
> +#define CY_REG_TCH_TMOUT		(CY_REG_ACT_INTRVL+1)
> +#define CY_REG_LP_INTRVL		(CY_REG_TCH_TMOUT+1)
> +#define CY_SOFT_RESET			((1 << 0))
> +#define CY_DEEP_SLEEP			((1 << 1))
> +#define CY_LOW_POWER			((1 << 2))
> +#define CY_MAXZ				255
> +#define CY_OK				0
> +#define CY_INIT				1
> +#define	CY_DLY_DFLT			10	/* ms */
> +#define CY_DLY_SYSINFO			20	/* ms */
> +#define CY_DLY_BL			300
> +#define CY_DLY_DNLOAD			100	/* ms */
> +#define CY_NUM_RETRY			4	/* max num touch data read */
> +
> +/* handshake bit in the hst_mode reg */
> +#define CY_HNDSHK_BIT			0x80
> +#ifdef CY_USE_HNDSHK
> +	#define CY_SEND_HNDSHK		1
> +#else
> +	#define CY_SEND_HNDSHK		0
> +#endif
> +
> +/* Bootloader File 0 offset */
> +#define CY_BL_FILE0			0x00
> +
> +/* Bootloader command directive */
> +#define CY_BL_CMD			0xFF
> +
> +/* Bootloader Initiate Bootload */
> +#define CY_BL_INIT_LOAD			0x38
> +
> +/* Bootloader Write a Block */
> +#define CY_BL_WRITE_BLK			0x39
> +
> +/* Bootloader Terminate Bootload */
> +#define CY_BL_TERMINATE			0x3B
> +
> +/* Bootloader Exit and Verify Checksum command */
> +#define CY_BL_EXIT			0xA5
> +
> +/* Bootloader default keys */
> +#define CY_BL_KEY0			0x00
> +#define CY_BL_KEY1			0x01
> +#define CY_BL_KEY2			0x02
> +#define CY_BL_KEY3			0x03
> +#define CY_BL_KEY4			0x04
> +#define CY_BL_KEY5			0x05
> +#define CY_BL_KEY6			0x06
> +#define CY_BL_KEY7			0x07
> +
> +/* Active Power state scanning/processing refresh interval */
> +#define CY_ACT_INTRVL_DFLT		0x00
> +
> +/* touch timeout for the Active power */
> +#define CY_TCH_TMOUT_DFLT		0xFF
> +
> +/* Low Power state scanning/processing refresh interval */
> +#define CY_LP_INTRVL_DFLT		0x0A
> +
> +#define CY_IDLE_STATE		0
> +#define CY_ACTIVE_STATE		1
> +#define CY_LOW_PWR_STATE		2
> +#define CY_SLEEP_STATE		3
> +
> +/* device mode bits */
> +#define CY_OP_MODE		0x00
> +#define CY_SYSINFO_MODE		0x10
> +
> +/* power mode select bits */
> +#define CY_SOFT_RESET_MODE		0x01	/* return to Bootloader mode */
> +#define CY_DEEP_SLEEP_MODE		0x02
> +#define CY_LOW_PWR_MODE		0x04
> +
> +#define CY_NUM_KEY			8
> +
> +#ifdef CY_USE_GEST
> +	#define CY_USE_GESTURES	1
> +#else
> +	#define CY_USE_GESTURES	0
> +#endif /* CY_USE_GESTURE_SIGNALS */
> +
> +#ifdef CY_USE_GEST_GRP1
> +	#define CY_GEST_GRP1	0x10
> +#else
> +	#define CY_GEST_GRP1	0x00
> +#endif	/* CY_USE_GEST_GRP1 */
> +#ifdef CY_USE_GEST_GRP2
> +	#define CY_GEST_GRP2	0x20
> +#else
> +	#define CY_GEST_GRP2	0x00
> +#endif	/* CY_USE_GEST_GRP2 */
> +#ifdef CY_USE_GEST_GRP3
> +	#define CY_GEST_GRP3	0x40
> +#else
> +	#define CY_GEST_GRP3	0x00
> +#endif	/* CY_USE_GEST_GRP3 */
> +#ifdef CY_USE_GEST_GRP4
> +	#define CY_GEST_GRP4	0x80
> +#else
> +	#define CY_GEST_GRP4	0x00
> +#endif	/* CY_USE_GEST_GRP4 */
> +
> +
> +struct cyttsp_platform_data {
> +	u32 maxx;
> +	u32 maxy;
> +	u32 flags;
> +	u8 gen;
> +	u8 use_st;
> +	u8 use_mt;
> +	u8 use_hndshk;
> +	u8 use_trk_id;
> +	u8 use_sleep;
> +	u8 use_gestures;
> +	u8 gest_set;
> +	u8 act_intrvl;
> +	u8 tch_tmout;
> +	u8 lp_intrvl;
> +	u8 power_state;
> +#ifdef CY_USE_I2C_DRIVER
> +	s32 (*init)(struct i2c_client *client);
> +	s32 (*resume)(struct i2c_client *client);
> +#endif
> +#ifdef CY_USE_SPI_DRIVER
> +	s32 (*init)(struct spi_device *spi);
> +	s32 (*resume)(struct spi_device *spi);
> +#endif
> +};
> +
> +/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */
> +struct cyttsp_gen3_xydata_t {
> +	u8 hst_mode;
> +	u8 tt_mode;
> +	u8 tt_stat;
> +	u16 x1 __attribute__ ((packed));
> +	u16 y1 __attribute__ ((packed));
> +	u8 z1;
> +	u8 touch12_id;
> +	u16 x2 __attribute__ ((packed));
> +	u16 y2 __attribute__ ((packed));
> +	u8 z2;
> +	u8 gest_cnt;
> +	u8 gest_id;
> +	u16 x3 __attribute__ ((packed));
> +	u16 y3 __attribute__ ((packed));
> +	u8 z3;
> +	u8 touch34_id;
> +	u16 x4 __attribute__ ((packed));
> +	u16 y4 __attribute__ ((packed));
> +	u8 z4;
> +	u8 tt_undef[3];
> +	u8 gest_set;
> +	u8 tt_reserved;
> +};

Do you really need this to be exported in the header file? If possible move it to the .c file.

> +
> +/* TrueTouch Standard Product Gen2 (Txx2xx) interface definition */
> +#define CY_GEN2_NOTOUCH		0x03	/* Both touches removed */
> +#define CY_GEN2_GHOST		0x02	/* ghost */
> +#define CY_GEN2_2TOUCH		0x03	/* 2 touch; no ghost */
> +#define CY_GEN2_1TOUCH		0x01	/* 1 touch only */
> +#define CY_GEN2_TOUCH2		0x01	/* 1st touch removed;
> +						 * 2nd touch remains */
> +struct cyttsp_gen2_xydata_t {
> +	u8 hst_mode;
> +	u8 tt_mode;
> +	u8 tt_stat;
> +	u16 x1 __attribute__ ((packed));
> +	u16 y1 __attribute__ ((packed));
> +	u8 z1;
> +	u8 evnt_idx;
> +	u16 x2 __attribute__ ((packed));
> +	u16 y2 __attribute__ ((packed));
> +	u8 tt_undef1;
> +	u8 gest_cnt;
> +	u8 gest_id;
> +	u8 tt_undef[14];
> +	u8 gest_set;
> +	u8 tt_reserved;
> +};
> +
> +/* TTSP System Information interface definition */
> +struct cyttsp_sysinfo_data_t {
> +	u8 hst_mode;
> +	u8 mfg_cmd;
> +	u8 mfg_stat;
> +	u8 cid[3];
> +	u8 tt_undef1;
> +	u8 uid[8];
> +	u8 bl_verh;
> +	u8 bl_verl;
> +	u8 tts_verh;
> +	u8 tts_verl;
> +	u8 app_idh;
> +	u8 app_idl;
> +	u8 app_verh;
> +	u8 app_verl;
> +	u8 tt_undef[6];
> +	u8 act_intrvl;
> +	u8 tch_tmout;
> +	u8 lp_intrvl;
> +};

Ditto.

> +
> +/* TTSP Bootloader Register Map interface definition */
> +#define CY_BL_CHKSUM_OK		0x01
> +struct cyttsp_bootloader_data_t {
> +	u8 bl_file;
> +	u8 bl_status;
> +	u8 bl_error;
> +	u8 blver_hi;
> +	u8 blver_lo;
> +	u8 bld_blver_hi;
> +	u8 bld_blver_lo;
> +	u8 ttspver_hi;
> +	u8 ttspver_lo;
> +	u8 appid_hi;
> +	u8 appid_lo;
> +	u8 appver_hi;
> +	u8 appver_lo;
> +	u8 cid_0;
> +	u8 cid_1;
> +	u8 cid_2;
> +};
> +
> +#define cyttsp_wake_data_t		cyttsp_gen3_xydata_t
> +#ifdef CY_DECLARE_GLOBALS
> +	#ifdef CY_INCLUDE_LOAD_FILE
> +		/* this file declares:
> +		 * firmware download block array (cyttsp_fw[]),
> +		 * the number of command block records (cyttsp_fw_records),
> +		 * and the version variables
> +		 */
> +		#include "cyttsp_fw.h"		/* imports cyttsp_fw[] array */
> +		#define cyttsp_app_load()	1
> +		#ifdef CY_FORCE_FW_UPDATE
> +			#define cyttsp_force_fw_load()	1
> +		#else
> +			#define cyttsp_force_fw_load()	0
> +		#endif
> +
> +	#else
> +		/* the following declarations are to allow
> +		 * some debugging capability
> +		 */
> +		unsigned char cyttsp_fw_tts_verh = 0x00;
> +		unsigned char cyttsp_fw_tts_verl = 0x01;
> +		unsigned char cyttsp_fw_app_idh = 0x02;
> +		unsigned char cyttsp_fw_app_idl = 0x03;
> +		unsigned char cyttsp_fw_app_verh = 0x04;
> +		unsigned char cyttsp_fw_app_verl = 0x05;
> +		unsigned char cyttsp_fw_cid_0 = 0x06;
> +		unsigned char cyttsp_fw_cid_1 = 0x07;
> +		unsigned char cyttsp_fw_cid_2 = 0x08;
> +		#define cyttsp_app_load()	0
> +		#define cyttsp_force_fw_load()	0
> +	#endif
> +	#define cyttsp_tts_verh()	cyttsp_fw_tts_verh
> +	#define cyttsp_tts_verl()	cyttsp_fw_tts_verl
> +	#define cyttsp_app_idh()	cyttsp_fw_app_idh
> +	#define cyttsp_app_idl()	cyttsp_fw_app_idl
> +	#define cyttsp_app_verh()	cyttsp_fw_app_verh
> +	#define cyttsp_app_verl()	cyttsp_fw_app_verl
> +	#define cyttsp_cid_0()		cyttsp_fw_cid_0
> +	#define cyttsp_cid_1()		cyttsp_fw_cid_1
> +	#define cyttsp_cid_2()		cyttsp_fw_cid_2
> +	#ifdef CY_USE_TEST_DATA
> +		static struct cyttsp_gen2_xydata_t tt_gen2_testray[] = {
> +		{0x00}, {0x00}, {0x04},
> +		{0x4000}, {0x8000}, {0x80},
> +		{0x03},
> +		{0x2000}, {0x1000}, {0x00},
> +		{0x00},
> +		{0x00},
> +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
> +		{0x00},
> +		{0x00}
> +		};
> +
> +		static struct cyttsp_gen3_xydata_t tt_gen3_testray[] = {
> +		{0x00}, {0x00}, {0x04},
> +		{0x4000}, {0x8000}, {0x80},
> +		{0x12},
> +		{0x2000}, {0x1000}, {0xA0},
> +		{0x00}, {0x00},
> +		{0x8000}, {0x4000}, {0xB0},
> +		{0x34},
> +		{0x4000}, {0x1000}, {0xC0},
> +		{0x00, 0x00, 0x00},
> +		{0x00},
> +		{0x00}
> +		};
> +	#endif /* CY_USE_TEST_DATA */
> +
> +#else
> +		extern u8 g_appload_ray[];
> +#endif
> +
> +#endif /* __CYTTSP_H__ */

---Trilok Soni


-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  7:31   ` Trilok Soni
@ 2010-07-13  7:55     ` Dmitry Torokhov
  2010-07-13  8:42       ` Trilok Soni
  2010-08-04 17:27       ` Kevin McNeely
  2010-07-19  9:28     ` Jean Delvare
  2010-08-04 17:22     ` Kevin McNeely
  2 siblings, 2 replies; 70+ messages in thread
From: Dmitry Torokhov @ 2010-07-13  7:55 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Kevin McNeely, David Brown, Fred, Samuel Ortiz, Eric Miao,
	Mark Brown, Simtec Linux Team, Arnaud Patard, Antonio Ospite,
	Henrik Rydberg, linux-input, linux-kernel, linux-i2c, khali,
	linux-arm-msm

On Tue, Jul 13, 2010 at 01:01:32PM +0530, Trilok Soni wrote:
> Hi Kevin,
> 
> Thanks for posting this driver.
> 
> Adding Jean Delvar for i2c bits.
> 
> On 7/13/2010 2:26 AM, Kevin McNeely wrote:
> > From: Fred <fwk@ubuntu.linuxcertified.com>
> 
> E-mail id looks wrong. Do you mean fwk@cypress.com?
> 
> > 
> > This is a new touchscreen driver for the Cypress Semiconductor
> > cyttsp family of devices.  This driver is for the i2c version
> > of cyttsp parts.
> 
> Please explain in commit text which exact version of the chips this driver is supporting.
> It is hard to make out that from this text.
> > 
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > ---
> >  drivers/input/touchscreen/Kconfig      |   13 +
> >  drivers/input/touchscreen/Makefile     |    1 +
> >  drivers/input/touchscreen/cyttsp-i2c.c | 2016 ++++++++++++++++++++++++++++++++
> >  include/linux/cyttsp.h                 |  649 ++++++++++
> 
> Please move this file to include/linux/input directory.
> 

Or even keep it in drivers/input/touchscreen/

> 
> > 
> > diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> > index 3b9d5e2..a7a69a0 100644
> > --- a/drivers/input/touchscreen/Kconfig
> > +++ b/drivers/input/touchscreen/Kconfig
> > @@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called tps6507x_ts.
> >  
> > +config TOUCHSCREEN_CYTTSP_I2C
> > +	default n
> 
> Do we need to provide this if it is no by default?
> 
> > +	tristate "Cypress TTSP i2c touchscreen"
> > +	depends on I2C
> > +	help
> > +	  Say Y here if you have a Cypress TTSP touchscreen
> > +	  connected to your system's i2c bus.
> 
> What is TTSP?
> 
> > +
> > +	  If unsure, say N.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called cyttsp_i2c.
> > +
> >  endif
> 

Since there is SPI part should we prepare for the support and split
bus-independent parts off? Are you working on SPI support?

> 
> > diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
> > new file mode 100644
> > index 0000000..8397aa1
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp-i2c.c
> > @@ -0,0 +1,2016 @@
> > +/* Source for:
> > + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
> > + * drivers/input/touchscreen/cyttsp-i2c.c
> 
> No file paths please. Already commented on it by Christoph.
> 
> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License along
> > + * with this program; if not, write to the Free Software Foundation, Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Cypress reserves the right to make changes without further notice
> > + * to the materials described herein. Cypress does not assume any
> > + * liability arising out of the application described herein.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> 
> I would like Dmitry to comment on it. Dmitry?
> 

Not a lwayer but I do not really see an issue here. It is still GPL and
they as copyright holders obviously can modify the code. What exactly
troubles you here?


> > + *
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/i2c.h>
> > +#include <linux/input.h>
> > +#include <linux/slab.h>
> > +#include <linux/gpio.h>
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/timer.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/byteorder/generic.h>
> > +#include <linux/bitops.h>
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +#include <linux/earlysuspend.h>
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> 
> We don't have early suspend support yet into the mainline kernel. Please remove this code from the driver.
> 
> > +
> > +#define CY_DECLARE_GLOBALS
> 
> Could you please explain what it does?
> 
> > +
> > +#include <linux/cyttsp.h>
> > +
> > +uint32_t cyttsp_tsdebug1 = 0xff;
> > +module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
> > +
> > +/* CY TTSP I2C Driver private data */
> > +struct cyttsp {
> > +	struct i2c_client *client;
> > +	struct input_dev *input;
> > +	struct work_struct work;
> > +	struct timer_list timer;
> > +	struct mutex mutex;
> > +	char phys[32];
> > +	struct cyttsp_platform_data *platform_data;
> > +	u8 num_prv_st_tch;
> > +	u16 act_trk[CY_NUM_TRK_ID];
> > +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> > +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> > +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> > +	atomic_t irq_enabled;
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +	struct early_suspend early_suspend;
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +};
> > +static u8 irq_cnt;		/* comparison counter with register valuw */
> 
> s/valuw/value 
> 
> > +static u32 irq_cnt_total;	/* total interrupts */
> > +static u32 irq_err_cnt;		/* count number of touch interrupts with err */
> > +#define CY_IRQ_CNT_MASK	0x000000FF	/* mapped for sizeof count in reg */
> > +#define CY_IRQ_CNT_REG	0x00		/* tt_undef[0]=reg 0x1B - Gen3 only */
> > +
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +static void cyttsp_early_suspend(struct early_suspend *handler);
> > +static void cyttsp_late_resume(struct early_suspend *handler);
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +
> > +static struct workqueue_struct *cyttsp_ts_wq;
> 
> Why there are so many global variables lying around?
> 
> > +
> > +
> > +/* ****************************************************************************
> > + * Prototypes for static functions
> > + * ************************************************************************** */
> > +static void cyttsp_xy_worker(struct work_struct *work);
> > +static irqreturn_t cyttsp_irq(int irq, void *handle);
> > +static int cyttsp_inlist(u16 prev_track[],
> > +			u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
> > +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> > +			u8 *new_loc, u8 num_touches);
> > +static int cyttsp_putbl(struct cyttsp *ts, int show,
> > +			int show_status, int show_version, int show_cid);
> > +static int __devinit cyttsp_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id);
> > +static int __devexit cyttsp_remove(struct i2c_client *client);
> > +static int cyttsp_resume(struct i2c_client *client);
> > +static int cyttsp_suspend(struct i2c_client *client, pm_message_t message);
> 
> Please re-order the functions in the driver such a way so that you don't need have these prototypes here.
> 
> > +
> > +/* Static variables */
> > +static struct cyttsp_gen3_xydata_t g_xy_data;
> > +static struct cyttsp_bootloader_data_t g_bl_data;
> > +static struct cyttsp_sysinfo_data_t g_sysinfo_data;
> 
> again globals?
> 
> > +static const struct i2c_device_id cyttsp_id[] = {
> > +	{ CY_I2C_NAME, 0 },  { }
> 
> Why dont you put ,{} at the next line.
> 
> > +};
> 
> You should not put driver name above, but it should be something like real chip name.
> 
> Say cy8ctXXX.
> 
> > +static u8 bl_cmd[] = {
> > +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> > +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> > +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> > +	CY_BL_KEY6, CY_BL_KEY7};
> 
> and what these keys does?
> 
> > +
> > +MODULE_DEVICE_TABLE(i2c, cyttsp_id);
> 
> Why it is not with cyttsp_id above?
> 
> > +
> > +static struct i2c_driver cyttsp_driver = {
> > +	.driver = {
> > +		.name = CY_I2C_NAME,
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe = cyttsp_probe,
> > +	.remove = __devexit_p(cyttsp_remove),
> > +	.suspend = cyttsp_suspend,
> > +	.resume = cyttsp_resume,
> > +	.id_table = cyttsp_id,
> > +};
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver");
> > +MODULE_AUTHOR("Cypress");
> 
> MODULE_ALIAS?
> 
> > +
> > +static ssize_t cyttsp_irq_status(struct device *dev,
> > +				struct device_attribute *attr, char *buf)
> > +{
> > +	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> > +	struct cyttsp *ts = i2c_get_clientdata(client);
> > +	return sprintf(buf, "%u\n", atomic_read(&ts->irq_enabled));
> > +}
> > +
> > +static ssize_t cyttsp_irq_enable(struct device *dev,
> > +				struct device_attribute *attr,
> > +				const char *buf, size_t size)
> > +{
> > +	struct i2c_client *client = container_of(dev, struct i2c_client, dev);
> > +	struct cyttsp *ts = i2c_get_clientdata(client);
> > +	int err = 0;
> > +	unsigned long value;
> > +
> > +	if (size > 2)
> > +		return -EINVAL;
> > +
> > +	err = strict_strtoul(buf, 10, &value);
> > +	if (err != 0)
> > +		return err;
> > +
> > +	switch (value) {
> > +	case 0:
> > +		if (atomic_cmpxchg(&ts->irq_enabled, 1, 0)) {
> > +			pr_info("touch irq disabled!\n");
> > +			disable_irq_nosync(ts->client->irq);

I do not believe that this achieves what you want.., You may reschedule
between cmpxchg and disable_irq_nosync().


Haven't looked any further yet...

-- 
Dmitry

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  7:55     ` Dmitry Torokhov
@ 2010-07-13  8:42       ` Trilok Soni
  2010-07-22 10:33         ` Trilok Soni
  2010-08-04 17:27       ` Kevin McNeely
  1 sibling, 1 reply; 70+ messages in thread
From: Trilok Soni @ 2010-07-13  8:42 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Kevin McNeely, David Brown, Fred, Samuel Ortiz, Eric Miao,
	Mark Brown, Simtec Linux Team, Arnaud Patard, Antonio Ospite,
	Henrik Rydberg, linux-input, linux-kernel, linux-i2c, khali,
	linux-arm-msm

On 7/13/2010 1:25 PM, Dmitry Torokhov wrote:
> On Tue, Jul 13, 2010 at 01:01:32PM +0530, Trilok Soni wrote:
>> Hi Kevin,
>>
>> Thanks for posting this driver.
>>
>> Adding Jean Delvar for i2c bits.
>>
>> On 7/13/2010 2:26 AM, Kevin McNeely wrote:
>>> From: Fred <fwk@ubuntu.linuxcertified.com>
>>
>> E-mail id looks wrong. Do you mean fwk@cypress.com?
>>
>>>
>>> This is a new touchscreen driver for the Cypress Semiconductor
>>> cyttsp family of devices.  This driver is for the i2c version
>>> of cyttsp parts.
>>
>> Please explain in commit text which exact version of the chips this driver is supporting.
>> It is hard to make out that from this text.
>>>
>>> Signed-off-by: Kevin McNeely <kev@cypress.com>
>>> ---
>>>  drivers/input/touchscreen/Kconfig      |   13 +
>>>  drivers/input/touchscreen/Makefile     |    1 +
>>>  drivers/input/touchscreen/cyttsp-i2c.c | 2016 ++++++++++++++++++++++++++++++++
>>>  include/linux/cyttsp.h                 |  649 ++++++++++
>>
>> Please move this file to include/linux/input directory.
>>
> 
> Or even keep it in drivers/input/touchscreen/

They are having platform data structure in this header file which might be accessed from the board-xxx.c
files under mach-xxx directories of ARM like architecture.

> 
>>
>>>
>>> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>>> index 3b9d5e2..a7a69a0 100644
>>> --- a/drivers/input/touchscreen/Kconfig
>>> +++ b/drivers/input/touchscreen/Kconfig
>>> @@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
>>>  	  To compile this driver as a module, choose M here: the
>>>  	  module will be called tps6507x_ts.
>>>  
>>> +config TOUCHSCREEN_CYTTSP_I2C
>>> +	default n
>>
>> Do we need to provide this if it is no by default?
>>
>>> +	tristate "Cypress TTSP i2c touchscreen"
>>> +	depends on I2C
>>> +	help
>>> +	  Say Y here if you have a Cypress TTSP touchscreen
>>> +	  connected to your system's i2c bus.
>>
>> What is TTSP?
>>
>>> +
>>> +	  If unsure, say N.
>>> +
>>> +	  To compile this driver as a module, choose M here: the
>>> +	  module will be called cyttsp_i2c.
>>> +
>>>  endif
>>
> 
> Since there is SPI part should we prepare for the support and split
> bus-independent parts off? Are you working on SPI support?

I don't think the current patch is divided neatly to drive this chip over
multiple bus protocols.

> 
>>
>>> diff --git a/drivers/input/touchscreen/cyttsp-i2c.c b/drivers/input/touchscreen/cyttsp-i2c.c
>>> new file mode 100644
>>> index 0000000..8397aa1
>>> --- /dev/null
>>> +++ b/drivers/input/touchscreen/cyttsp-i2c.c
>>> @@ -0,0 +1,2016 @@
>>> +/* Source for:
>>> + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
>>> + * drivers/input/touchscreen/cyttsp-i2c.c
>>
>> No file paths please. Already commented on it by Christoph.
>>
>>> + *
>>> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
>>> + *
>>> + * This program is free software; you can redistribute it and/or
>>> + * modify it under the terms of the GNU General Public License
>>> + * version 2, and only version 2, as published by the
>>> + * Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope that it will be useful,
>>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> + * GNU General Public License for more details.
>>> + *
>>> + * You should have received a copy of the GNU General Public License along
>>> + * with this program; if not, write to the Free Software Foundation, Inc.,
>>> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
>>> + *
>>> + * Cypress reserves the right to make changes without further notice
>>> + * to the materials described herein. Cypress does not assume any
>>> + * liability arising out of the application described herein.
>>> + *
>>> + * Contact Cypress Semiconductor at www.cypress.com
>>
>> I would like Dmitry to comment on it. Dmitry?
>>
> 
> Not a lwayer but I do not really see an issue here. It is still GPL and
> they as copyright holders obviously can modify the code. What exactly
> troubles you here?

No issue from my side too.

---Trilok Soni

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  7:31   ` Trilok Soni
  2010-07-13  7:55     ` Dmitry Torokhov
@ 2010-07-19  9:28     ` Jean Delvare
  2010-08-04 17:22     ` Kevin McNeely
  2 siblings, 0 replies; 70+ messages in thread
From: Jean Delvare @ 2010-07-19  9:28 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Kevin McNeely, Dmitry Torokhov, David Brown, Fred, Samuel Ortiz,
	Eric Miao, Mark Brown, Simtec Linux Team, Arnaud Patard,
	Antonio Ospite, Henrik Rydberg, linux-input, linux-kernel,
	linux-i2c, linux-arm-msm

On Tue, 13 Jul 2010 13:01:32 +0530, Trilok Soni wrote:
> Hi Kevin,
> 
> Thanks for posting this driver.
> 
> Adding Jean Delvar for i2c bits.

-ENOTIME, sorry.

-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  8:42       ` Trilok Soni
@ 2010-07-22 10:33         ` Trilok Soni
  2010-07-27 15:20           ` Kevin McNeely
  0 siblings, 1 reply; 70+ messages in thread
From: Trilok Soni @ 2010-07-22 10:33 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Kevin McNeely, David Brown, Samuel Ortiz, Eric Miao, Mark Brown,
	Simtec Linux Team, Arnaud Patard, Antonio Ospite, Henrik Rydberg,
	linux-input, linux-kernel, linux-i2c, khali, linux-arm-msm

Hi Kevin,

On 7/13/2010 2:12 PM, Trilok Soni wrote:
> On 7/13/2010 1:25 PM, Dmitry Torokhov wrote:
>> On Tue, Jul 13, 2010 at 01:01:32PM +0530, Trilok Soni wrote:
>>> Hi Kevin,
>>>
>>> Thanks for posting this driver.

Are you going to post updated version of this patch, addressing review comments?

---Trilok Soni

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-22 10:33         ` Trilok Soni
@ 2010-07-27 15:20           ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-07-27 15:20 UTC (permalink / raw)
  To: Trilok Soni, Dmitry Torokhov
  Cc: David Brown, Samuel Ortiz, Eric Miao, Mark Brown,
	Simtec Linux Team, Arnaud Patard, Antonio Ospite, Henrik Rydberg,
	linux-input, linux-kernel, linux-i2c, khali, linux-arm-msm

Hi Trilok,

Yes, I am working on a new refactored version.  I will be looking to
post the new version soon.

-kev

-----Original Message-----
From: Trilok Soni [mailto:tsoni@codeaurora.org] 
Sent: Thursday, July 22, 2010 3:33 AM
To: Dmitry Torokhov
Cc: Kevin McNeely; David Brown; Samuel Ortiz; Eric Miao; Mark Brown;
Simtec Linux Team; Arnaud Patard; Antonio Ospite; Henrik Rydberg;
linux-input@vger.kernel.org; linux-kernel@vger.kernel.org;
linux-i2c@vger.kernel.org; khali@linux-fr.org;
linux-arm-msm@vger.kernel.org
Subject: Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit

Hi Kevin,

On 7/13/2010 2:12 PM, Trilok Soni wrote:
> On 7/13/2010 1:25 PM, Dmitry Torokhov wrote:
>> On Tue, Jul 13, 2010 at 01:01:32PM +0530, Trilok Soni wrote:
>>> Hi Kevin,
>>>
>>> Thanks for posting this driver.

Are you going to post updated version of this patch, addressing review
comments?

---Trilok Soni

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
Forum.

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  2:34   ` Christoph Fritz
@ 2010-08-04 16:30     ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-04 16:30 UTC (permalink / raw)
  To: Christoph Fritz
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Mark Brown, Simtec Linux Team, Arnaud Patard,
	Antonio Ospite, Henrik Rydberg, linux-input, linux-kernel

Hi Christopher,


> -----Original Message-----
> From: Christoph Fritz [mailto:chf.fritz@googlemail.com]
> Sent: Monday, July 12, 2010 7:34 PM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Fred; Samuel Ortiz;
Eric
> Miao; Mark Brown; Simtec Linux Team; Arnaud Patard; Antonio Ospite;
> Henrik Rydberg; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org; chf.fritz@googlemail.com
> Subject: Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
> 
> On Mon, 2010-07-12 at 13:56 -0700, Kevin McNeely wrote:
> > From: Fred <fwk@ubuntu.linuxcertified.com>
> >
> > This is a new touchscreen driver for the Cypress Semiconductor
> > cyttsp family of devices.  This driver is for the i2c version
> > of cyttsp parts.
> >
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > ---
> >  drivers/input/touchscreen/Kconfig      |   13 +
> >  drivers/input/touchscreen/Makefile     |    1 +
> >  drivers/input/touchscreen/cyttsp-i2c.c | 2016
> ++++++++++++++++++++++++++++++++
> >  include/linux/cyttsp.h                 |  649 ++++++++++
> >  4 files changed, 2679 insertions(+), 0 deletions(-)
> >  create mode 100644 drivers/input/touchscreen/cyttsp-i2c.c
> >  create mode 100644 include/linux/cyttsp.h
> >
> > diff --git a/drivers/input/touchscreen/Kconfig
> b/drivers/input/touchscreen/Kconfig
> > index 3b9d5e2..a7a69a0 100644
> > --- a/drivers/input/touchscreen/Kconfig
> > +++ b/drivers/input/touchscreen/Kconfig
> > @@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called tps6507x_ts.
> >
> > +config TOUCHSCREEN_CYTTSP_I2C
> > +	default n
> > +	tristate "Cypress TTSP i2c touchscreen"
> > +	depends on I2C
> > +	help
> > +	  Say Y here if you have a Cypress TTSP touchscreen
> > +	  connected to your system's i2c bus.
> > +
> > +	  If unsure, say N.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called cyttsp_i2c.
> 
> below it's named cyttsp-i2c

This will be fixed.

> 
> > +
> >  endif
> > diff --git a/drivers/input/touchscreen/Makefile
> b/drivers/input/touchscreen/Makefile
> > index 497964a..2026cb8 100644
> > --- a/drivers/input/touchscreen/Makefile
> > +++ b/drivers/input/touchscreen/Makefile
> > @@ -47,3 +47,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)
+=
> mainstone-wm97xx.o
> >  obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
> >  obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
> >  obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
> > +obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp-i2c.o
> > diff --git a/drivers/input/touchscreen/cyttsp-i2c.c
> b/drivers/input/touchscreen/cyttsp-i2c.c
> > new file mode 100644
> > index 0000000..8397aa1
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp-i2c.c
> > @@ -0,0 +1,2016 @@
> > +/* Source for:
> > + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
> > + * drivers/input/touchscreen/cyttsp-i2c.c
> 
> To quote Dmitry Torokhov:
> "No file names  (and especially paths) in comment blocks please -
makes
> harder to move stuff around."
> 

Paths and filenames will be removed from the headers.

> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> along
> > + * with this program; if not, write to the Free Software
Foundation,
> Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Cypress reserves the right to make changes without further
notice
> > + * to the materials described herein. Cypress does not assume any
> > + * liability arising out of the application described herein.
> 
> Sure, Cypress can engineer what they want. The warranty is already
> covered by GPL.
> 

The paragraph will be removed from the headers.


> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> 
> Maintainer or at least a email ad would be nice I think.
> 

An email address will be added to the headers.

> > + *
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/i2c.h>
> > +#include <linux/input.h>
> > +#include <linux/slab.h>
> > +#include <linux/gpio.h>
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/timer.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/byteorder/generic.h>
> > +#include <linux/bitops.h>
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +#include <linux/earlysuspend.h>
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +
> > +#define CY_DECLARE_GLOBALS
> > +
> > +#include <linux/cyttsp.h>
> 
> Would it be possible to move cyttsp.h to the local folder?
> 

The cyttsp.h file needs to be in the global folder to support board
configuration files.  The cyttsp.h contents will be reduced to the
minimum and a local include file will be added.


> > +
> > +uint32_t cyttsp_tsdebug1 = 0xff;
> 
> why can't this be static?
> why is it in the header too?
> 

Globals and statics will be removed.  Data will either be in context
structure or automatic.

> > +module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
> > +
> > +/* CY TTSP I2C Driver private data */
> > +struct cyttsp {
> > +	struct i2c_client *client;
> > +	struct input_dev *input;
> > +	struct work_struct work;
> > +	struct timer_list timer;
> > +	struct mutex mutex;
> > +	char phys[32];
> > +	struct cyttsp_platform_data *platform_data;
> > +	u8 num_prv_st_tch;
> > +	u16 act_trk[CY_NUM_TRK_ID];
> > +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> > +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> > +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> > +	atomic_t irq_enabled;
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +	struct early_suspend early_suspend;
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +};
> > +static u8 irq_cnt;		/* comparison counter with register
valuw
> */
> > +static u32 irq_cnt_total;	/* total interrupts */
> > +static u32 irq_err_cnt;		/* count number of touch
interrupts
> with err */
> > +#define CY_IRQ_CNT_MASK	0x000000FF	/* mapped for sizeof
count in
> reg */
> > +#define CY_IRQ_CNT_REG	0x00		/* tt_undef[0]=reg 0x1B
-
> Gen3 only */
> > +
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +static void cyttsp_early_suspend(struct early_suspend *handler);
> > +static void cyttsp_late_resume(struct early_suspend *handler);
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +
> > +static struct workqueue_struct *cyttsp_ts_wq;
> > +
> > +
> > +/*
>
***********************************************************************
> *****
> > + * Prototypes for static functions
> > + *
>
***********************************************************************
> *** */
> 
> star gap, and more than 80 chars
> 

New code will not have lines greater than 80 chars.

> > +static void cyttsp_xy_worker(struct work_struct *work);
> > +static irqreturn_t cyttsp_irq(int irq, void *handle);
> > +static int cyttsp_inlist(u16 prev_track[],
> > +			u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
> > +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> > +			u8 *new_loc, u8 num_touches);
> > +static int cyttsp_putbl(struct cyttsp *ts, int show,
> > +			int show_status, int show_version, int
show_cid);
> > +static int __devinit cyttsp_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id);
> > +static int __devexit cyttsp_remove(struct i2c_client *client);
> > +static int cyttsp_resume(struct i2c_client *client);
> > +static int cyttsp_suspend(struct i2c_client *client, pm_message_t
> message);
> 
> could these prototypes be avoided?
> 

Prototypes will be removed by reordering functions.

> > +
> > +/* Static variables */
> > +static struct cyttsp_gen3_xydata_t g_xy_data;
> > +static struct cyttsp_bootloader_data_t g_bl_data;
> > +static struct cyttsp_sysinfo_data_t g_sysinfo_data;
> > +static const struct i2c_device_id cyttsp_id[] = {
> > +	{ CY_I2C_NAME, 0 },  { }
> > +};
> > +static u8 bl_cmd[] = {
> > +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> > +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> > +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> > +	CY_BL_KEY6, CY_BL_KEY7};
> > +
> > +MODULE_DEVICE_TABLE(i2c, cyttsp_id);
> > +
> > +static struct i2c_driver cyttsp_driver = {
> > +	.driver = {
> > +		.name = CY_I2C_NAME,
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe = cyttsp_probe,
> > +	.remove = __devexit_p(cyttsp_remove),
> > +	.suspend = cyttsp_suspend,
> > +	.resume = cyttsp_resume,
> > +	.id_table = cyttsp_id,
> > +};
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen
> driver");
> > +MODULE_AUTHOR("Cypress");
> 
> Why not re-factoring the whole driver to keep consistency with other
> touchpad drivers?


The new code will be refactored.

> A maintainer to contact or at least a email-ad would be nice I think.
> You could use scripts/checkpatch.pl to find some warnings.
> 
> [..]
> 

The new code will have an email address and will be scanned with
checkpatch.

Thank you Christopher for your review.


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  6:48   ` Henrik Rydberg
@ 2010-08-04 16:38     ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-04 16:38 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Mark Brown, Simtec Linux Team, Arnaud Patard,
	Antonio Ospite, linux-input, linux-kernel

Hi Henrik,

> -----Original Message-----
> From: Henrik Rydberg [mailto:rydberg@euromail.se]
> Sent: Monday, July 12, 2010 11:48 PM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Fred; Samuel Ortiz;
Eric
> Miao; Mark Brown; Simtec Linux Team; Arnaud Patard; Antonio Ospite;
> linux-input@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
> 
> Kevin McNeely wrote:
> > From: Fred <fwk@ubuntu.linuxcertified.com>
> >
> > This is a new touchscreen driver for the Cypress Semiconductor
> > cyttsp family of devices.  This driver is for the i2c version
> > of cyttsp parts.
> >
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > ---
> 
> This driver contains too much code. I am wondering if the device
> actually
> supports tracking id, or whether it is emulated in the driver code? If
> tracking
> is not well supported in hardware, then please use MT protocol A and
> remove the
> usage of ABS_MT_TRACKING_ID and the logic around it. If tracking is
> indeed well
> supported in the hardware, then please use MT protocol B.
> 
> Thanks,
> Henrik

I have a new code set that has been refactored and easier to follow.
The driver supports both Protocol A and Protocol B.
The Cypress TTSP parts have well supported Tracking ID's, so the driver
provides protocol B reporting option.
The driver also handles reporting without the Tracking ID's for Protocol
A option.
A user selects which option in the board configuration file.

Thank you Henrik for your review.



---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  7:31   ` Trilok Soni
  2010-07-13  7:55     ` Dmitry Torokhov
  2010-07-19  9:28     ` Jean Delvare
@ 2010-08-04 17:22     ` Kevin McNeely
  2 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-04 17:22 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Dmitry Torokhov, David Brown, Fred, Samuel Ortiz, Eric Miao,
	Mark Brown, Simtec Linux Team, Arnaud Patard, Antonio Ospite,
	Henrik Rydberg, linux-input, linux-kernel, linux-i2c, khali,
	linux-arm-msm

Hi Trilok,

> -----Original Message-----
> From: Trilok Soni [mailto:tsoni@codeaurora.org]
> Sent: Tuesday, July 13, 2010 12:32 AM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Fred; Samuel Ortiz; Eric Miao; Mark
> Brown; Simtec Linux Team; Arnaud Patard; Antonio Ospite; Henrik
> Rydberg; linux-input@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-i2c@vger.kernel.org; khali@linux-fr.org; linux-arm-
> msm@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
> 
> Hi Kevin,
> 
> Thanks for posting this driver.
> 
> Adding Jean Delvar for i2c bits.
> 
> On 7/13/2010 2:26 AM, Kevin McNeely wrote:
> > From: Fred <fwk@ubuntu.linuxcertified.com>
> 
> E-mail id looks wrong. Do you mean fwk@cypress.com?
> 
> >
> > This is a new touchscreen driver for the Cypress Semiconductor
> > cyttsp family of devices.  This driver is for the i2c version
> > of cyttsp parts.
> 
> Please explain in commit text which exact version of the chips this
> driver is supporting.
> It is hard to make out that from this text.
> >
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > ---
> >  drivers/input/touchscreen/Kconfig      |   13 +
> >  drivers/input/touchscreen/Makefile     |    1 +
> >  drivers/input/touchscreen/cyttsp-i2c.c | 2016
> ++++++++++++++++++++++++++++++++
> >  include/linux/cyttsp.h                 |  649 ++++++++++
> 
> Please move this file to include/linux/input directory.
> 
> 
> >
> > diff --git a/drivers/input/touchscreen/Kconfig
> b/drivers/input/touchscreen/Kconfig
> > index 3b9d5e2..a7a69a0 100644
> > --- a/drivers/input/touchscreen/Kconfig
> > +++ b/drivers/input/touchscreen/Kconfig
> > @@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called tps6507x_ts.
> >
> > +config TOUCHSCREEN_CYTTSP_I2C
> > +	default n
> 
> Do we need to provide this if it is no by default?
> 

The new refactored code has new core file added to build dependencies.

> > +	tristate "Cypress TTSP i2c touchscreen"
> > +	depends on I2C
> > +	help
> > +	  Say Y here if you have a Cypress TTSP touchscreen
> > +	  connected to your system's i2c bus.
> 
> What is TTSP?
> 

TTSP=TrueTouch Standard Product.  Headers will be updated to show this.

> > +
> > +	  If unsure, say N.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called cyttsp_i2c.
> > +
> >  endif
> 
> 
> > diff --git a/drivers/input/touchscreen/cyttsp-i2c.c
> b/drivers/input/touchscreen/cyttsp-i2c.c
> > new file mode 100644
> > index 0000000..8397aa1
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp-i2c.c
> > @@ -0,0 +1,2016 @@
> > +/* Source for:
> > + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
> > + * drivers/input/touchscreen/cyttsp-i2c.c
> 
> No file paths please. Already commented on it by Christoph.
> 

Paths and filenames will be removed from headers.

> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> along
> > + * with this program; if not, write to the Free Software
Foundation,
> Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Cypress reserves the right to make changes without further
notice
> > + * to the materials described herein. Cypress does not assume any
> > + * liability arising out of the application described herein.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> 
> I would like Dmitry to comment on it. Dmitry?
> 

The paragraph will be removed from headers.

> > + *
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/i2c.h>
> > +#include <linux/input.h>
> > +#include <linux/slab.h>
> > +#include <linux/gpio.h>
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/timer.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/byteorder/generic.h>
> > +#include <linux/bitops.h>
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +#include <linux/earlysuspend.h>
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> 
> We don't have early suspend support yet into the mainline kernel.
> Please remove this code from the driver.
> 

Early suspend will be removed from the driver.

> > +
> > +#define CY_DECLARE_GLOBALS
> 
> Could you please explain what it does?
> 

This has been removed.  No globals will be used.

> > +
> > +#include <linux/cyttsp.h>
> > +
> > +uint32_t cyttsp_tsdebug1 = 0xff;
> > +module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
> > +
> > +/* CY TTSP I2C Driver private data */
> > +struct cyttsp {
> > +	struct i2c_client *client;
> > +	struct input_dev *input;
> > +	struct work_struct work;
> > +	struct timer_list timer;
> > +	struct mutex mutex;
> > +	char phys[32];
> > +	struct cyttsp_platform_data *platform_data;
> > +	u8 num_prv_st_tch;
> > +	u16 act_trk[CY_NUM_TRK_ID];
> > +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> > +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> > +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> > +	atomic_t irq_enabled;
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +	struct early_suspend early_suspend;
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +};
> > +static u8 irq_cnt;		/* comparison counter with register
valuw
> */
> 
> s/valuw/value
> 
> > +static u32 irq_cnt_total;	/* total interrupts */
> > +static u32 irq_err_cnt;		/* count number of touch
interrupts
> with err */
> > +#define CY_IRQ_CNT_MASK	0x000000FF	/* mapped for sizeof
count in
> reg */
> > +#define CY_IRQ_CNT_REG	0x00		/* tt_undef[0]=reg 0x1B
-
> Gen3 only */
> > +
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +static void cyttsp_early_suspend(struct early_suspend *handler);
> > +static void cyttsp_late_resume(struct early_suspend *handler);
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +
> > +static struct workqueue_struct *cyttsp_ts_wq;
> 
> Why there are so many global variables lying around?
> 

Globals have been removed.

> > +
> > +
> > +/*
>
***********************************************************************
> *****
> > + * Prototypes for static functions
> > + *
>
***********************************************************************
> *** */
> > +static void cyttsp_xy_worker(struct work_struct *work);
> > +static irqreturn_t cyttsp_irq(int irq, void *handle);
> > +static int cyttsp_inlist(u16 prev_track[],
> > +			u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
> > +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> > +			u8 *new_loc, u8 num_touches);
> > +static int cyttsp_putbl(struct cyttsp *ts, int show,
> > +			int show_status, int show_version, int
show_cid);
> > +static int __devinit cyttsp_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id);
> > +static int __devexit cyttsp_remove(struct i2c_client *client);
> > +static int cyttsp_resume(struct i2c_client *client);
> > +static int cyttsp_suspend(struct i2c_client *client, pm_message_t
> message);
> 
> Please re-order the functions in the driver such a way so that you
> don't need have these prototypes here.
> 

Functions have been reordered to eliminate prototypes.

> > +
> > +/* Static variables */
> > +static struct cyttsp_gen3_xydata_t g_xy_data;
> > +static struct cyttsp_bootloader_data_t g_bl_data;
> > +static struct cyttsp_sysinfo_data_t g_sysinfo_data;
> 
> again globals?
> 
> > +static const struct i2c_device_id cyttsp_id[] = {
> > +	{ CY_I2C_NAME, 0 },  { }
> 
> Why dont you put ,{} at the next line.
> 
> > +};
> 
> You should not put driver name above, but it should be something like
> real chip name.
> 
> Say cy8ctXXX.

The parts are called TTSP parts.
The driver supports all TTSP parts.
Sample part numbers will be added to the headers.

> 
> > +static u8 bl_cmd[] = {
> > +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> > +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> > +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> > +	CY_BL_KEY6, CY_BL_KEY7};
> 
> and what these keys does?
> 

The key must be sent to the device on bootup to move the device to
operational mode.

> > +
> > +MODULE_DEVICE_TABLE(i2c, cyttsp_id);
> 
> Why it is not with cyttsp_id above?
> 

This has been moved in the new code.

> > +
> > +static struct i2c_driver cyttsp_driver = {
> > +	.driver = {
> > +		.name = CY_I2C_NAME,
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe = cyttsp_probe,
> > +	.remove = __devexit_p(cyttsp_remove),
> > +	.suspend = cyttsp_suspend,
> > +	.resume = cyttsp_resume,
> > +	.id_table = cyttsp_id,
> > +};
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen
> driver");
> > +MODULE_AUTHOR("Cypress");
> 
> MODULE_ALIAS?
> 

This has been added to new code.

> > +
> > +static ssize_t cyttsp_irq_status(struct device *dev,
> > +				struct device_attribute *attr, char
*buf)
> > +{
> > +	struct i2c_client *client = container_of(dev, struct i2c_client,
> dev);
> > +	struct cyttsp *ts = i2c_get_clientdata(client);
> > +	return sprintf(buf, "%u\n", atomic_read(&ts->irq_enabled));
> > +}
> > +
> > +static ssize_t cyttsp_irq_enable(struct device *dev,
> > +				struct device_attribute *attr,
> > +				const char *buf, size_t size)
> > +{
> > +	struct i2c_client *client = container_of(dev, struct i2c_client,
> dev);
> > +	struct cyttsp *ts = i2c_get_clientdata(client);
> > +	int err = 0;
> > +	unsigned long value;
> > +
> > +	if (size > 2)
> > +		return -EINVAL;
> > +
> > +	err = strict_strtoul(buf, 10, &value);
> > +	if (err != 0)
> > +		return err;
> > +
> > +	switch (value) {
> > +	case 0:
> > +		if (atomic_cmpxchg(&ts->irq_enabled, 1, 0)) {
> > +			pr_info("touch irq disabled!\n");
> > +			disable_irq_nosync(ts->client->irq);
> > +		}
> > +		err = size;
> > +		break;
> > +	case 1:
> > +		if (!atomic_cmpxchg(&ts->irq_enabled, 0, 1)) {
> > +			pr_info("touch irq enabled!\n");
> > +			enable_irq(ts->client->irq);
> > +		}
> > +		err = size;
> > +		break;
> > +	default:
> > +		pr_info("cyttsp_irq_enable failed -> irq_enabled =
%d\n",
> > +		atomic_read(&ts->irq_enabled));
> > +		err = -EINVAL;
> > +		break;
> > +	}
> > +
> > +	return err;
> > +}
> > +
> > +static DEVICE_ATTR(irq_enable, 0777, cyttsp_irq_status,
> cyttsp_irq_enable);
> 
> 
> Please explain why you are providing this sysfs entries?
> 

The sysfs entried were to support dynamic debug enables.
These have been removed.
The new code has replaced the custom debug.

> > +
> > +/* The cyttsp_xy_worker function reads the XY coordinates and sends
> them to
> > + * the input layer.  It is scheduled from the interrupt (or timer).
> > + */
> > +void cyttsp_xy_worker(struct work_struct *work)
> > +{
> > +	struct cyttsp *ts = container_of(work, struct cyttsp, work);
> > +	u8 id, tilt, rev_x, rev_y;
> > +	u8 i, loc;
> > +	u8 prv_tch;		/* number of previous touches */
> > +	u8 cur_tch;	/* number of current touches */
> > +	u16 tmp_trk[CY_NUM_MT_TCH_ID];
> > +	u16 snd_trk[CY_NUM_MT_TCH_ID];
> > +	u16 cur_trk[CY_NUM_TRK_ID];
> > +	u16 cur_st_tch[CY_NUM_ST_TCH_ID];
> > +	u16 cur_mt_tch[CY_NUM_MT_TCH_ID];
> > +	/* if NOT CY_USE_TRACKING_ID then
> > +	 * only uses CY_NUM_MT_TCH_ID positions */
> > +	u16 cur_mt_pos[CY_NUM_TRK_ID][2];
> > +	/* if NOT CY_USE_TRACKING_ID then
> > +	 * only uses CY_NUM_MT_TCH_ID positions */
> > +	u8 cur_mt_z[CY_NUM_TRK_ID];
> > +	u8 curr_tool_width;
> > +	u16 st_x1, st_y1;
> > +	u8 st_z1;
> > +	u16 st_x2, st_y2;
> > +	u8 st_z2;
> > +	s32 retval;
> > +
> > +	cyttsp_xdebug("TTSP worker start 1:\n");
> > +
> > +	/* get event data from CYTTSP device */
> > +	i = CY_NUM_RETRY;
> > +	do {
> > +		retval = i2c_smbus_read_i2c_block_data(ts->client,
> > +			CY_REG_BASE,
> > +			sizeof(struct cyttsp_gen3_xydata_t), (u8
> *)&g_xy_data);
> > +	} while ((retval < CY_OK) && --i);
> > +
> > +	if (retval < CY_OK) {
> > +		/* return immediately on
> > +		 * failure to read device on the i2c bus */
> > +		goto exit_xy_worker;
> > +	}
> > +
> > +	cyttsp_xdebug("TTSP worker start 2:\n");
> > +
> > +	/* compare own irq counter with the device irq counter */
> > +	if (ts->client->irq) {
> > +		u8 host_reg;
> > +		u8 cur_cnt;
> > +		if (ts->platform_data->use_hndshk) {
> > +
> > +			host_reg = g_xy_data.hst_mode & CY_HNDSHK_BIT ?
> > +				g_xy_data.hst_mode & ~CY_HNDSHK_BIT :
> > +				g_xy_data.hst_mode | CY_HNDSHK_BIT;
> > +			retval =
i2c_smbus_write_i2c_block_data(ts->client,
> > +				CY_REG_BASE, sizeof(host_reg),
&host_reg);
> > +		}
> > +		cur_cnt = g_xy_data.tt_undef[CY_IRQ_CNT_REG];
> > +		irq_cnt_total++;
> > +		irq_cnt++;
> > +		if (irq_cnt != cur_cnt) {
> > +			irq_err_cnt++;
> > +			cyttsp_debug("i_c_ER: dv=%d fw=%d hm=%02X t=%lu
> te=%lu\n", \
> > +				irq_cnt, \
> > +				cur_cnt, g_xy_data.hst_mode, \
> > +				(unsigned long)irq_cnt_total, \
> > +				(unsigned long)irq_err_cnt);
> > +		} else {
> > +			cyttsp_debug("i_c_ok: dv=%d fw=%d hm=%02X t=%lu
> te=%lu\n", \
> > +				irq_cnt, \
> > +				cur_cnt, g_xy_data.hst_mode, \
> > +				(unsigned long)irq_cnt_total, \
> > +				(unsigned long)irq_err_cnt);
> > +		}
> > +		irq_cnt = cur_cnt;
> > +	}
> > +
> > +	/* Get the current num touches and return if there are no
touches
> */
> > +	if ((GET_BOOTLOADERMODE(g_xy_data.tt_mode) == 1) ||
> > +		(GET_HSTMODE(g_xy_data.hst_mode) != CY_OK)) {
> > +		u8 host_reg, tries;
> > +		/* the TTSP device has suffered spurious reset or mode
> switch */
> > +		cyttsp_debug( \
> > +			"Spurious err opmode (tt_mode=%02X
hst_mode=%02X)\n",
> \
> > +			g_xy_data.tt_mode, g_xy_data.hst_mode);
> > +		cyttsp_debug("Reset TTSP Device; Terminating active
> tracks\n");
> > +		/* terminate all active tracks */
> > +		cur_tch = CY_NTCH;
> > +		/* reset TTSP part and take it back out of Bootloader
mode
> */
> > +		host_reg = CY_SOFT_RESET_MODE;
> > +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> > +			CY_REG_BASE,
> > +			sizeof(host_reg), &host_reg);
> > +		tries = 0;
> > +		do {
> > +			mdelay(1000);
> > +
> > +			/* set arg2 to non-0 to activate */
> > +			retval = cyttsp_putbl(ts, 1, false, false,
false);
> > +		} while (!(retval < CY_OK) &&
> > +			!GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
> > +			!(g_bl_data.bl_file ==
> > +			CY_OP_MODE + CY_LOW_PWR_MODE) &&
> > +			tries++ < 10);
> > +		/* switch back to operational mode */
> > +		if (GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
> > +			retval =
i2c_smbus_write_i2c_block_data(ts->client,
> > +				CY_REG_BASE,
> > +				sizeof(bl_cmd), bl_cmd);
> > +			tries = 0;
> > +			do {
> > +				mdelay(1000);
> > +				cyttsp_putbl(ts, 1, false, false,
false);
> > +			} while (GET_BOOTLOADERMODE(g_bl_data.bl_status)
&&
> > +				tries++ < 10);
> > +		}
> > +		if (!(retval < CY_OK)) {
> > +			host_reg = CY_OP_MODE
> > +				/* + CY_LOW_PWR_MODE */;
> > +			retval =
i2c_smbus_write_i2c_block_data(ts->client,
> > +				CY_REG_BASE,
> > +				sizeof(host_reg), &host_reg);
> > +			/* wait for TTSP Device to complete switch to Op
mode
> */
> > +			mdelay(1000);
> > +		}
> > +		goto exit_xy_worker;
> > +	} else {
> > +		cur_tch = GET_NUM_TOUCHES(g_xy_data.tt_stat);
> > +		if (IS_LARGE_AREA(g_xy_data.tt_stat)) {
> > +			/* terminate all active tracks */
> > +			cur_tch = CY_NTCH;
> > +			cyttsp_debug("Large obj detect (tt_stat=0x%02X).
> Terminate act trks\n", \
> > +			    g_xy_data.tt_stat);
> > +		} else if (cur_tch > CY_NUM_MT_TCH_ID) {
> > +			/* if the number of fingers on the touch surface
> > +			 * is more than the maximum then
> > +			 * there will be no new track information
> > +			 * even for the original touches.
> > +			 * Therefore, terminate all active tracks.
> > +			 */
> > +			cur_tch = CY_NTCH;
> > +			cyttsp_debug("Num touch err (tt_stat=0x%02X).
> Terminate act trks\n", \
> > +			    g_xy_data.tt_stat);
> > +		}
> > +	}
> > +
> > +	/* set tool size */
> > +	curr_tool_width = CY_SMALL_TOOL_WIDTH;
> > +
> > +	/* translate Gen2 interface data into comparable Gen3 data */
> > +	if (ts->platform_data->gen == CY_GEN2) {
> > +		struct cyttsp_gen2_xydata_t *pxy_gen2_data;
> > +		pxy_gen2_data = (struct cyttsp_gen2_xydata_t
> *)(&g_xy_data);
> > +
> > +		/* use test data? */
> > +		cyttsp_testdat(&g_xy_data, &tt_gen2_testray, \
> > +			sizeof(struct cyttsp_gen3_xydata_t));
> > +
> > +		if (pxy_gen2_data->evnt_idx == CY_GEN2_NOTOUCH) {
> > +			cur_tch = 0;
> > +		} else if (cur_tch == CY_GEN2_GHOST) {
> > +			cur_tch = 0;
> > +		} else if (cur_tch == CY_GEN2_2TOUCH) {
> > +			/* stuff artificial track ID1 and ID2 */
> > +			g_xy_data.touch12_id = 0x12;
> > +			g_xy_data.z1 = CY_MAXZ;
> > +			g_xy_data.z2 = CY_MAXZ;
> > +			cur_tch--;			/* 2 touches */
> > +		} else if (cur_tch == CY_GEN2_1TOUCH) {
> > +			/* stuff artificial track ID1 and ID2 */
> > +			g_xy_data.touch12_id = 0x12;
> > +			g_xy_data.z1 = CY_MAXZ;
> > +			g_xy_data.z2 = CY_NTCH;
> > +			if (pxy_gen2_data->evnt_idx == CY_GEN2_TOUCH2) {
> > +				/* push touch 2 data into touch1
> > +				 * (first finger up; second finger down)
*/
> > +				/* stuff artificial track ID1 for touch2
info
> */
> > +				g_xy_data.touch12_id = 0x20;
> > +				/* stuff touch 1 with touch 2 coordinate
data
> */
> > +				g_xy_data.x1 = g_xy_data.x2;
> > +				g_xy_data.y1 = g_xy_data.y2;
> > +			}
> > +		} else {
> > +			cur_tch = 0;
> > +		}
> > +	} else {
> > +		/* use test data? */
> > +		cyttsp_testdat(&g_xy_data, &tt_gen3_testray, \
> > +			sizeof(struct cyttsp_gen3_xydata_t));
> > +	}
> > +
> > +
> > +
> > +	/* clear current active track ID array and count previous
touches
> */
> > +	for (id = 0, prv_tch = CY_NTCH;
> > +		id < CY_NUM_TRK_ID; id++) {
> > +		cur_trk[id] = CY_NTCH;
> > +		prv_tch += ts->act_trk[id];
> > +	}
> > +
> > +	/* send no events if no previous touches and no new touches */
> > +	if ((prv_tch == CY_NTCH) &&
> > +		((cur_tch == CY_NTCH) ||
> > +		(cur_tch > CY_NUM_MT_TCH_ID))) {
> > +		goto exit_xy_worker;
> > +	}
> > +
> > +	cyttsp_debug("prev=%d  curr=%d\n", prv_tch, cur_tch);
> > +
> > +	for (id = 0; id < CY_NUM_ST_TCH_ID; id++) {
> > +		/* clear current single touches array */
> > +		cur_st_tch[id] = CY_IGNR_TCH;
> > +	}
> > +
> > +	/* clear single touch positions */
> > +	st_x1 = CY_NTCH;
> > +	st_y1 = CY_NTCH;
> > +	st_z1 = CY_NTCH;
> > +	st_x2 = CY_NTCH;
> > +	st_y2 = CY_NTCH;
> > +	st_z2 = CY_NTCH;
> > +
> > +	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +		/* clear current multi-touches array and
> > +		 * multi-touch positions/z */
> > +		cur_mt_tch[id] = CY_IGNR_TCH;
> > +	}
> > +
> > +	if (ts->platform_data->use_trk_id) {
> > +		for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +			cur_mt_pos[id][CY_XPOS] = 0;
> > +			cur_mt_pos[id][CY_YPOS] = 0;
> > +			cur_mt_z[id] = 0;
> > +		}
> > +	} else {
> > +		for (id = 0; id < CY_NUM_TRK_ID; id++) {
> > +			cur_mt_pos[id][CY_XPOS] = 0;
> > +			cur_mt_pos[id][CY_YPOS] = 0;
> > +			cur_mt_z[id] = 0;
> > +		}
> > +	}
> > +
> > +	/* Determine if display is tilted */
> > +	if (FLIP_DATA(ts->platform_data->flags))
> > +		tilt = true;
> > +	else
> > +		tilt = false;
> > +
> > +	/* Check for switch in origin */
> > +	if (REVERSE_X(ts->platform_data->flags))
> > +		rev_x = true;
> > +	else
> > +		rev_x = false;
> > +
> > +	if (REVERSE_Y(ts->platform_data->flags))
> > +		rev_y = true;
> > +	else
> > +		rev_y = false;
> > +
> > +	if (cur_tch) {
> > +		struct cyttsp_gen2_xydata_t *pxy_gen2_data;
> > +		struct cyttsp_gen3_xydata_t *pxy_gen3_data;
> > +		switch (ts->platform_data->gen) {
> > +		case CY_GEN2: {
> > +			pxy_gen2_data =
> > +				(struct cyttsp_gen2_xydata_t
*)(&g_xy_data);
> > +			cyttsp_xdebug("TTSP Gen2 report:\n");
> > +			cyttsp_xdebug("%02X %02X %02X\n", \
> > +				pxy_gen2_data->hst_mode, \
> > +				pxy_gen2_data->tt_mode, \
> > +				pxy_gen2_data->tt_stat);
> > +			cyttsp_xdebug("%04X %04X %02X  %02X\n", \
> > +				pxy_gen2_data->x1, \
> > +				pxy_gen2_data->y1, \
> > +				pxy_gen2_data->z1, \
> > +				pxy_gen2_data->evnt_idx);
> > +			cyttsp_xdebug("%04X %04X %02X\n", \
> > +				pxy_gen2_data->x2, \
> > +				pxy_gen2_data->y2, \
> > +				pxy_gen2_data->tt_undef1);
> > +			cyttsp_xdebug("%02X %02X %02X\n", \
> > +				pxy_gen2_data->gest_cnt, \
> > +				pxy_gen2_data->gest_id, \
> > +				pxy_gen2_data->gest_set);
> > +			break;
> > +		}
> > +		case CY_GEN3:
> > +		default: {
> > +			pxy_gen3_data =
> > +				(struct cyttsp_gen3_xydata_t
*)(&g_xy_data);
> > +			cyttsp_xdebug("TTSP Gen3 report:\n");
> > +			cyttsp_xdebug("%02X %02X %02X\n", \
> > +				pxy_gen3_data->hst_mode,
> > +				pxy_gen3_data->tt_mode,
> > +				pxy_gen3_data->tt_stat);
> > +			cyttsp_xdebug("%04X %04X %02X  %02X", \
> > +				pxy_gen3_data->x1,
> > +				pxy_gen3_data->y1,
> > +				pxy_gen3_data->z1, \
> > +				pxy_gen3_data->touch12_id);
> > +			cyttsp_xdebug("%04X %04X %02X\n", \
> > +				pxy_gen3_data->x2, \
> > +				pxy_gen3_data->y2, \
> > +				pxy_gen3_data->z2);
> > +			cyttsp_xdebug("%02X %02X %02X\n", \
> > +				pxy_gen3_data->gest_cnt, \
> > +				pxy_gen3_data->gest_id, \
> > +				pxy_gen3_data->gest_set);
> > +			cyttsp_xdebug("%04X %04X %02X  %02X\n", \
> > +				pxy_gen3_data->x3, \
> > +				pxy_gen3_data->y3, \
> > +				pxy_gen3_data->z3, \
> > +				pxy_gen3_data->touch34_id);
> > +			cyttsp_xdebug("%04X %04X %02X\n", \
> > +				pxy_gen3_data->x4, \
> > +				pxy_gen3_data->y4, \
> > +				pxy_gen3_data->z4);
> > +			break;
> > +		}
> > +		}
> > +	}
> > +
> > +	/* process the touches */
> > +	switch (cur_tch) {
> > +	case 4: {
> > +		g_xy_data.x4 = be16_to_cpu(g_xy_data.x4);
> > +		g_xy_data.y4 = be16_to_cpu(g_xy_data.y4);
> > +		if (tilt)
> > +			FLIP_XY(g_xy_data.x4, g_xy_data.y4);
> > +
> > +		if (rev_x) {
> > +			g_xy_data.x4 =
> > +				INVERT_X(g_xy_data.x4,
ts->platform_data-
> >maxx);
> > +		}
> > +		if (rev_y) {
> > +			g_xy_data.y4 =
> > +				INVERT_X(g_xy_data.y4,
ts->platform_data-
> >maxy);
> > +		}
> > +		id = GET_TOUCH4_ID(g_xy_data.touch34_id);
> > +		if (ts->platform_data->use_trk_id) {
> > +			cur_mt_pos[CY_MT_TCH4_IDX][CY_XPOS] =
> > +				g_xy_data.x4;
> > +			cur_mt_pos[CY_MT_TCH4_IDX][CY_YPOS] =
> > +				g_xy_data.y4;
> > +			cur_mt_z[CY_MT_TCH4_IDX] = g_xy_data.z4;
> > +		} else {
> > +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x4;
> > +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y4;
> > +			cur_mt_z[id] = g_xy_data.z4;
> > +		}
> > +		cur_mt_tch[CY_MT_TCH4_IDX] = id;
> > +		cur_trk[id] = CY_TCH;
> > +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> > +			CY_NUM_TRK_ID) {
> > +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> > +				st_x1 = g_xy_data.x4;
> > +				st_y1 = g_xy_data.y4;
> > +				st_z1 = g_xy_data.z4;
> > +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> > +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] ==
id) {
> > +				st_x2 = g_xy_data.x4;
> > +				st_y2 = g_xy_data.y4;
> > +				st_z2 = g_xy_data.z4;
> > +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> > +			}
> > +		}
> > +		cyttsp_xdebug("4th XYZ:% 3d,% 3d,% 3d  ID:% 2d\n\n", \
> > +			g_xy_data.x4, g_xy_data.y4, g_xy_data.z4, \
> > +			(g_xy_data.touch34_id & 0x0F));
> > +		/* do not break */
> > +	}
> > +	case 3: {
> > +		g_xy_data.x3 = be16_to_cpu(g_xy_data.x3);
> > +		g_xy_data.y3 = be16_to_cpu(g_xy_data.y3);
> > +		if (tilt)
> > +			FLIP_XY(g_xy_data.x3, g_xy_data.y3);
> > +
> > +		if (rev_x) {
> > +			g_xy_data.x3 =
> > +				INVERT_X(g_xy_data.x3,
ts->platform_data-
> >maxx);
> > +		}
> > +		if (rev_y) {
> > +			g_xy_data.y3 =
> > +				INVERT_X(g_xy_data.y3,
ts->platform_data-
> >maxy);
> > +		}
> > +		id = GET_TOUCH3_ID(g_xy_data.touch34_id);
> > +		if (ts->platform_data->use_trk_id) {
> > +			cur_mt_pos[CY_MT_TCH3_IDX][CY_XPOS] =
> > +				g_xy_data.x3;
> > +			cur_mt_pos[CY_MT_TCH3_IDX][CY_YPOS] =
> > +				g_xy_data.y3;
> > +			cur_mt_z[CY_MT_TCH3_IDX] = g_xy_data.z3;
> > +		} else {
> > +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x3;
> > +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y3;
> > +			cur_mt_z[id] = g_xy_data.z3;
> > +		}
> > +		cur_mt_tch[CY_MT_TCH3_IDX] = id;
> > +		cur_trk[id] = CY_TCH;
> > +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> > +			CY_NUM_TRK_ID) {
> > +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> > +				st_x1 = g_xy_data.x3;
> > +				st_y1 = g_xy_data.y3;
> > +				st_z1 = g_xy_data.z3;
> > +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> > +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] ==
id) {
> > +				st_x2 = g_xy_data.x3;
> > +				st_y2 = g_xy_data.y3;
> > +				st_z2 = g_xy_data.z3;
> > +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> > +			}
> > +		}
> > +		cyttsp_xdebug("3rd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
> > +			g_xy_data.x3, g_xy_data.y3, g_xy_data.z3, \
> > +			((g_xy_data.touch34_id >> 4) & 0x0F));
> > +		/* do not break */
> > +	}
> > +	case 2: {
> > +		g_xy_data.x2 = be16_to_cpu(g_xy_data.x2);
> > +		g_xy_data.y2 = be16_to_cpu(g_xy_data.y2);
> > +		if (tilt)
> > +			FLIP_XY(g_xy_data.x2, g_xy_data.y2);
> > +
> > +		if (rev_x) {
> > +			g_xy_data.x2 =
> > +				INVERT_X(g_xy_data.x2,
ts->platform_data-
> >maxx);
> > +		}
> > +		if (rev_y) {
> > +			g_xy_data.y2 =
> > +				INVERT_X(g_xy_data.y2,
ts->platform_data-
> >maxy);
> > +		}
> > +		id = GET_TOUCH2_ID(g_xy_data.touch12_id);
> > +		if (ts->platform_data->use_trk_id) {
> > +			cur_mt_pos[CY_MT_TCH2_IDX][CY_XPOS] =
> > +				g_xy_data.x2;
> > +			cur_mt_pos[CY_MT_TCH2_IDX][CY_YPOS] =
> > +				g_xy_data.y2;
> > +			cur_mt_z[CY_MT_TCH2_IDX] = g_xy_data.z2;
> > +		} else {
> > +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x2;
> > +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y2;
> > +			cur_mt_z[id] = g_xy_data.z2;
> > +		}
> > +		cur_mt_tch[CY_MT_TCH2_IDX] = id;
> > +		cur_trk[id] = CY_TCH;
> > +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> > +			CY_NUM_TRK_ID) {
> > +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> > +				st_x1 = g_xy_data.x2;
> > +				st_y1 = g_xy_data.y2;
> > +				st_z1 = g_xy_data.z2;
> > +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> > +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] ==
id) {
> > +				st_x2 = g_xy_data.x2;
> > +				st_y2 = g_xy_data.y2;
> > +				st_z2 = g_xy_data.z2;
> > +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> > +			}
> > +		}
> > +		cyttsp_xdebug("2nd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
> > +			g_xy_data.x2, g_xy_data.y2, g_xy_data.z2, \
> > +			(g_xy_data.touch12_id & 0x0F));
> > +		/* do not break */
> > +	}
> > +	case 1:	{
> > +		g_xy_data.x1 = be16_to_cpu(g_xy_data.x1);
> > +		g_xy_data.y1 = be16_to_cpu(g_xy_data.y1);
> > +		if (tilt)
> > +			FLIP_XY(g_xy_data.x1, g_xy_data.y1);
> > +
> > +		if (rev_x) {
> > +			g_xy_data.x1 =
> > +				INVERT_X(g_xy_data.x1,
ts->platform_data-
> >maxx);
> > +		}
> > +		if (rev_y) {
> > +			g_xy_data.y1 =
> > +				INVERT_X(g_xy_data.y1,
ts->platform_data-
> >maxy);
> > +		}
> > +		id = GET_TOUCH1_ID(g_xy_data.touch12_id);
> > +		if (ts->platform_data->use_trk_id) {
> > +			cur_mt_pos[CY_MT_TCH1_IDX][CY_XPOS] =
> > +				g_xy_data.x1;
> > +			cur_mt_pos[CY_MT_TCH1_IDX][CY_YPOS] =
> > +				g_xy_data.y1;
> > +			cur_mt_z[CY_MT_TCH1_IDX] = g_xy_data.z1;
> > +		} else {
> > +			cur_mt_pos[id][CY_XPOS] = g_xy_data.x1;
> > +			cur_mt_pos[id][CY_YPOS] = g_xy_data.y1;
> > +			cur_mt_z[id] = g_xy_data.z1;
> > +		}
> > +		cur_mt_tch[CY_MT_TCH1_IDX] = id;
> > +		cur_trk[id] = CY_TCH;
> > +		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
> > +			CY_NUM_TRK_ID) {
> > +			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
> > +				st_x1 = g_xy_data.x1;
> > +				st_y1 = g_xy_data.y1;
> > +				st_z1 = g_xy_data.z1;
> > +				cur_st_tch[CY_ST_FNGR1_IDX] = id;
> > +			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] ==
id) {
> > +				st_x2 = g_xy_data.x1;
> > +				st_y2 = g_xy_data.y1;
> > +				st_z2 = g_xy_data.z1;
> > +				cur_st_tch[CY_ST_FNGR2_IDX] = id;
> > +			}
> > +		}
> > +		cyttsp_xdebug("1st XYZ:% 3d,% 3d,% 3d  ID:% 2d\n", \
> > +			g_xy_data.x1, g_xy_data.y1, g_xy_data.z1, \
> > +			((g_xy_data.touch12_id >> 4) & 0x0F));
> > +		break;
> > +	}
> > +	case 0:
> > +	default:{
> > +		break;
> > +	}
> > +	}
> > +
> > +	/* handle Single Touch signals */
> > +	if (ts->platform_data->use_st) {
> > +		cyttsp_xdebug("ST STEP 0 - ST1 ID=%d  ST2 ID=%d\n", \
> > +			cur_st_tch[CY_ST_FNGR1_IDX], \
> > +			cur_st_tch[CY_ST_FNGR2_IDX]);
> > +		if (cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) {
> > +			/* reassign finger 1 and 2 positions to new
tracks */
> > +			if (cur_tch > 0) {
> > +				/* reassign st finger1 */
> > +				if (ts->platform_data->use_trk_id) {
> > +					id = CY_MT_TCH1_IDX;
> > +					cur_st_tch[CY_ST_FNGR1_IDX] =
> cur_mt_tch[id];
> > +				} else {
> > +					id =
GET_TOUCH1_ID(g_xy_data.touch12_id);
> > +					cur_st_tch[CY_ST_FNGR1_IDX] =
id;
> > +				}
> > +				st_x1 = cur_mt_pos[id][CY_XPOS];
> > +				st_y1 = cur_mt_pos[id][CY_YPOS];
> > +				st_z1 = cur_mt_z[id];
> > +				cyttsp_xdebug("ST STEP 1 - ST1
ID=%3d\n", \
> > +					cur_st_tch[CY_ST_FNGR1_IDX]);
> > +				if ((cur_tch > 1) &&
> > +					(cur_st_tch[CY_ST_FNGR2_IDX] >
> > +					CY_NUM_TRK_ID)) {
> > +					/* reassign st finger2 */
> > +					if (cur_tch > 1) {
> > +						if
(ts->platform_data->use_trk_id)
> {
> > +							id =
CY_MT_TCH2_IDX;
> > +
cur_st_tch[CY_ST_FNGR2_IDX] =
> cur_mt_tch[id];
> > +						} else {
> > +							id =
> GET_TOUCH2_ID(g_xy_data.touch12_id);
> > +
cur_st_tch[CY_ST_FNGR2_IDX] =
> id;
> > +						}
> > +						st_x2 =
cur_mt_pos[id][CY_XPOS];
> > +						st_y2 =
cur_mt_pos[id][CY_YPOS];
> > +						st_z2 = cur_mt_z[id];
> > +						cyttsp_xdebug("ST STEP 2
- ST2
> ID=%3d\n", \
> > +
cur_st_tch[CY_ST_FNGR2_IDX]);
> > +					}
> > +				}
> > +			}
> > +		} else if (cur_st_tch[CY_ST_FNGR2_IDX] > CY_NUM_TRK_ID)
{
> > +			if (cur_tch > 1) {
> > +				/* reassign st finger2 */
> > +				if (ts->platform_data->use_trk_id) {
> > +					/* reassign st finger2 */
> > +					id = CY_MT_TCH2_IDX;
> > +					cur_st_tch[CY_ST_FNGR2_IDX] =
> > +						cur_mt_tch[id];
> > +				} else {
> > +					/* reassign st finger2 */
> > +					id =
GET_TOUCH2_ID(g_xy_data.touch12_id);
> > +					cur_st_tch[CY_ST_FNGR2_IDX] =
id;
> > +				}
> > +				st_x2 = cur_mt_pos[id][CY_XPOS];
> > +				st_y2 = cur_mt_pos[id][CY_YPOS];
> > +				st_z2 = cur_mt_z[id];
> > +				cyttsp_xdebug("ST STEP 3 - ST2
ID=%3d\n", \
> > +					cur_st_tch[CY_ST_FNGR2_IDX]);
> > +			}
> > +		}
> > +		/* if the 1st touch is missing and there is a 2nd touch,
> > +		 * then set the 1st touch to 2nd touch and terminate 2nd
> touch
> > +		 */
> > +		if ((cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) &&
> > +		    (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID)) {
> > +			st_x1 = st_x2;
> > +			st_y1 = st_y2;
> > +			st_z1 = st_z2;
> > +			cur_st_tch[CY_ST_FNGR1_IDX] =
> > +				cur_st_tch[CY_ST_FNGR2_IDX];
> > +			cur_st_tch[CY_ST_FNGR2_IDX] =
> > +				CY_IGNR_TCH;
> > +		}
> > +		/* if the 2nd touch ends up equal to the 1st touch,
> > +		 * then just report a single touch */
> > +		if (cur_st_tch[CY_ST_FNGR1_IDX] ==
> > +			cur_st_tch[CY_ST_FNGR2_IDX]) {
> > +			cur_st_tch[CY_ST_FNGR2_IDX] =
> > +				CY_IGNR_TCH;
> > +		}
> > +		/* set Single Touch current event signals */
> > +		if (cur_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) {
> > +			input_report_abs(ts->input,
> > +				ABS_X, st_x1);
> > +			input_report_abs(ts->input,
> > +				ABS_Y, st_y1);
> > +			input_report_abs(ts->input,
> > +				ABS_PRESSURE, st_z1);
> > +			input_report_key(ts->input,
> > +				BTN_TOUCH,
> > +				CY_TCH);
> > +			input_report_abs(ts->input,
> > +				ABS_TOOL_WIDTH,
> > +				curr_tool_width);
> > +			cyttsp_debug("ST->F1:%3d X:%3d Y:%3d Z:%3d\n", \
> > +				cur_st_tch[CY_ST_FNGR1_IDX], \
> > +				st_x1, st_y1, st_z1);
> > +			if (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID)
{
> > +				input_report_key(ts->input, BTN_2,
CY_TCH);
> > +				input_report_abs(ts->input, ABS_HAT0X,
st_x2);
> > +				input_report_abs(ts->input, ABS_HAT0Y,
st_y2);
> > +				cyttsp_debug("ST->F2:%3d X:%3d Y:%3d
Z:%3d\n",
> \
> > +					cur_st_tch[CY_ST_FNGR2_IDX],
> > +					st_x2, st_y2, st_z2);
> > +			} else {
> > +				input_report_key(ts->input,
> > +					BTN_2,
> > +					CY_NTCH);
> > +			}
> > +		} else {
> > +			input_report_abs(ts->input, ABS_PRESSURE,
CY_NTCH);
> > +			input_report_key(ts->input, BTN_TOUCH, CY_NTCH);
> > +			input_report_key(ts->input, BTN_2, CY_NTCH);
> > +		}
> > +		/* update platform data for the current single touch
info
> */
> > +		ts->prv_st_tch[CY_ST_FNGR1_IDX] =
> cur_st_tch[CY_ST_FNGR1_IDX];
> > +		ts->prv_st_tch[CY_ST_FNGR2_IDX] =
> cur_st_tch[CY_ST_FNGR2_IDX];
> > +
> > +	}
> > +
> > +	/* handle Multi-touch signals */
> > +	if (ts->platform_data->use_mt) {
> > +		if (ts->platform_data->use_trk_id) {
> > +			/* terminate any previous touch where the track
> > +			 * is missing from the current event */
> > +			for (id = 0; id < CY_NUM_TRK_ID; id++) {
> > +				if ((ts->act_trk[id] != CY_NTCH) &&
> > +					(cur_trk[id] == CY_NTCH)) {
> > +					input_report_abs(ts->input,
> > +						ABS_MT_TRACKING_ID,
> > +						id);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_TOUCH_MAJOR,
> > +						CY_NTCH);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_WIDTH_MAJOR,
> > +						curr_tool_width);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_X,
> > +
ts->prv_mt_pos[id][CY_XPOS]);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_Y,
> > +
ts->prv_mt_pos[id][CY_YPOS]);
> > +					CY_MT_SYNC(ts->input);
> > +					ts->act_trk[id] = CY_NTCH;
> > +					ts->prv_mt_pos[id][CY_XPOS] = 0;
> > +					ts->prv_mt_pos[id][CY_YPOS] = 0;
> > +				}
> > +			}
> > +			/* set Multi-Touch current event signals */
> > +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +				if (cur_mt_tch[id] < CY_NUM_TRK_ID) {
> > +					input_report_abs(ts->input,
> > +						ABS_MT_TRACKING_ID,
> > +						cur_mt_tch[id]);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_TOUCH_MAJOR,
> > +						cur_mt_z[id]);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_WIDTH_MAJOR,
> > +						curr_tool_width);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_X,
> > +
cur_mt_pos[id][CY_XPOS]);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_Y,
> > +
cur_mt_pos[id][CY_YPOS]);
> > +					CY_MT_SYNC(ts->input);
> > +					ts->act_trk[id] = CY_TCH;
> > +					ts->prv_mt_pos[id][CY_XPOS] =
> > +						cur_mt_pos[id][CY_XPOS];
> > +					ts->prv_mt_pos[id][CY_YPOS] =
> > +						cur_mt_pos[id][CY_YPOS];
> > +				}
> > +			}
> > +		} else {
> > +			/* set temporary track array elements to voids
*/
> > +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +				tmp_trk[id] = CY_IGNR_TCH;
> > +				snd_trk[id] = CY_IGNR_TCH;
> > +			}
> > +
> > +			/* get what is currently active */
> > +			for (i = 0, id = 0;
> > +				id < CY_NUM_TRK_ID && i <
CY_NUM_MT_TCH_ID;
> > +				id++) {
> > +				if (cur_trk[id] == CY_TCH) {
> > +					/* only incr counter if track
found */
> > +					tmp_trk[i] = id;
> > +					i++;
> > +				}
> > +			}
> > +			cyttsp_xdebug("T1: t0=%d, t1=%d, t2=%d,
t3=%d\n", \
> > +				tmp_trk[0], tmp_trk[1], tmp_trk[2], \
> > +				tmp_trk[3]);
> > +			cyttsp_xdebug("T1: p0=%d, p1=%d, p2=%d,
p3=%d\n", \
> > +				ts->prv_mt_tch[0], ts->prv_mt_tch[1], \
> > +				ts->prv_mt_tch[2], ts->prv_mt_tch[3]);
> > +
> > +			/* pack in still active previous touches */
> > +			for (id = 0, prv_tch = 0;
> > +				id < CY_NUM_MT_TCH_ID; id++) {
> > +				if (tmp_trk[id] < CY_NUM_TRK_ID) {
> > +					if
(cyttsp_inlist(ts->prv_mt_tch,
> > +						tmp_trk[id], &loc,
> > +						CY_NUM_MT_TCH_ID)) {
> > +						loc &= CY_NUM_MT_TCH_ID
- 1;
> > +						snd_trk[loc] =
tmp_trk[id];
> > +						prv_tch++;
> > +						cyttsp_xdebug("inlist
s[%d]=%d
> t[%d]=%d l=%d p=%d\n", \
> > +							loc,
snd_trk[loc], \
> > +							id, tmp_trk[id],
\
> > +							loc, prv_tch);
> > +					} else {
> > +						cyttsp_xdebug("not
inlist s[%d]=%d
> t[%d]=%d l=%d \n", \
> > +							id, snd_trk[id],
\
> > +							id, tmp_trk[id],
\
> > +							loc);
> > +					}
> > +				}
> > +			}
> > +			cyttsp_xdebug("S1: s0=%d, s1=%d, s2=%d, s3=%d
> p=%d\n", \
> > +				snd_trk[0], snd_trk[1], snd_trk[2], \
> > +				snd_trk[3], prv_tch);
> > +
> > +			/* pack in new touches */
> > +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +				if (tmp_trk[id] < CY_NUM_TRK_ID) {
> > +					if (!cyttsp_inlist(snd_trk,
tmp_trk[id],
> &loc, CY_NUM_MT_TCH_ID)) {
> > +						cyttsp_xdebug("not
inlist t[%d]=%d
> l=%d\n", \
> > +							id, tmp_trk[id],
loc);
> > +						if
> (cyttsp_next_avail_inlist(snd_trk, &loc, CY_NUM_MT_TCH_ID)) {
> > +							loc &=
CY_NUM_MT_TCH_ID - 1;
> > +							snd_trk[loc] =
tmp_trk[id];
> > +
cyttsp_xdebug("put inlist
> s[%d]=%d t[%d]=%d\n",
> > +								loc,
snd_trk[loc], id,
> tmp_trk[id]);
> > +						}
> > +					} else {
> > +						cyttsp_xdebug("is in
list s[%d]=%d
> t[%d]=%d loc=%d\n", \
> > +							id, snd_trk[id],
id,
> tmp_trk[id], loc);
> > +					}
> > +				}
> > +			}
> > +			cyttsp_xdebug("S2: s0=%d, s1=%d, s2=%d,
s3=%d\n", \
> > +				snd_trk[0], snd_trk[1],
> > +				snd_trk[2], snd_trk[3]);
> > +
> > +			/* sync motion event signals for each current
touch
> */
> > +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +				/* z will either be 0 (NOTOUCH) or
> > +				 * some pressure (TOUCH) */
> > +				cyttsp_xdebug("MT0 prev[%d]=%d
temp[%d]=%d
> send[%d]=%d\n", \
> > +					id, ts->prv_mt_tch[id], \
> > +					id, tmp_trk[id], \
> > +					id, snd_trk[id]);
> > +				if (snd_trk[id] < CY_NUM_TRK_ID) {
> > +					input_report_abs(ts->input,
> > +						ABS_MT_TOUCH_MAJOR,
> > +						cur_mt_z[snd_trk[id]]);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_WIDTH_MAJOR,
> > +						curr_tool_width);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_X,
> > +
cur_mt_pos[snd_trk[id]][CY_XPOS]);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_Y,
> > +
cur_mt_pos[snd_trk[id]][CY_YPOS]);
> > +					CY_MT_SYNC(ts->input);
> > +					cyttsp_debug("MT1->TID:%2d X:%3d
Y:%3d
> Z:%3d touch-sent\n", \
> > +						snd_trk[id], \
> > +
cur_mt_pos[snd_trk[id]][CY_XPOS], \
> > +
cur_mt_pos[snd_trk[id]][CY_YPOS], \
> > +						cur_mt_z[snd_trk[id]]);
> > +				} else if (ts->prv_mt_tch[id] <
CY_NUM_TRK_ID)
> {
> > +					/* void out this touch */
> > +					input_report_abs(ts->input,
> > +						ABS_MT_TOUCH_MAJOR,
> > +						CY_NTCH);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_WIDTH_MAJOR,
> > +						curr_tool_width);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_X,
> > +						ts->prv_mt_pos[ts-
> >prv_mt_tch[id]][CY_XPOS]);
> > +					input_report_abs(ts->input,
> > +						ABS_MT_POSITION_Y,
> > +						ts->prv_mt_pos[ts-
> >prv_mt_tch[id]][CY_YPOS]);
> > +					CY_MT_SYNC(ts->input);
> > +					cyttsp_debug("MT2->TID:%2d X:%3d
Y:%3d
> Z:%3d lift off-sent\n", \
> > +						ts->prv_mt_tch[id], \
> > +						ts->prv_mt_pos[ts-
> >prv_mt_tch[id]][CY_XPOS], \
> > +						ts->prv_mt_pos[ts-
> >prv_mt_tch[id]][CY_YPOS], \
> > +						CY_NTCH);
> > +				} else {
> > +					/* do not stuff any signals for
this
> > +					 * previously and currently
> > +					 * void touches */
> > +					cyttsp_xdebug("MT3->send[%d]=%d
- No
> touch - NOT sent\n", \
> > +							id,
snd_trk[id]);
> > +				}
> > +			}
> > +
> > +			/* save current posted tracks to
> > +			 * previous track memory */
> > +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +				ts->prv_mt_tch[id] = snd_trk[id];
> > +				ts->prv_mt_pos[snd_trk[id]][CY_XPOS] =
> > +
cur_mt_pos[snd_trk[id]][CY_XPOS];
> > +				ts->prv_mt_pos[snd_trk[id]][CY_YPOS] =
> > +
cur_mt_pos[snd_trk[id]][CY_YPOS];
> > +				cyttsp_xdebug("MT4->TID:%2d X:%3d Y:%3d
Z:%3d
> save for previous\n", \
> > +					snd_trk[id], \
> > +
ts->prv_mt_pos[snd_trk[id]][CY_XPOS], \
> > +
ts->prv_mt_pos[snd_trk[id]][CY_YPOS], \
> > +					CY_NTCH);
> > +			}
> > +			for (id = 0; id < CY_NUM_TRK_ID; id++)
> > +				ts->act_trk[id] = CY_NTCH;
> > +			for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
> > +				if (snd_trk[id] < CY_NUM_TRK_ID)
> > +					ts->act_trk[snd_trk[id]] =
CY_TCH;
> > +			}
> > +		}
> > +	}
> > +
> > +	/* handle gestures */
> > +	if (ts->platform_data->use_gestures) {
> > +		if (g_xy_data.gest_id) {
> > +			input_report_key(ts->input,
> > +				BTN_3, CY_TCH);
> > +			input_report_abs(ts->input,
> > +				ABS_HAT1X, g_xy_data.gest_id);
> > +			input_report_abs(ts->input,
> > +				ABS_HAT2Y, g_xy_data.gest_cnt);
> > +		}
> > +	}
> > +
> > +	/* signal the view motion event */
> > +	input_sync(ts->input);
> > +
> > +	for (id = 0; id < CY_NUM_TRK_ID; id++) {
> > +		/* update platform data for the current MT information
*/
> > +		ts->act_trk[id] = cur_trk[id];
> > +	}
> > +
> > +exit_xy_worker:
> > +	if (cyttsp_disable_touch) {
> > +		/* Turn off the touch interrupts */
> > +		cyttsp_debug("Not enabling touch\n");
> > +	} else {
> > +		if (ts->client->irq == 0) {
> > +			/* restart event timer */
> > +			mod_timer(&ts->timer, jiffies +
TOUCHSCREEN_TIMEOUT);
> > +		} else {
> > +			/* re-enable the interrupt after processing */
> > +			enable_irq(ts->client->irq);
> > +		}
> > +	}
> > +	return;
> > +}
> > +
> > +static int cyttsp_inlist(u16 prev_track[], u8 cur_trk_id,
> > +			u8 *prev_loc, u8 num_touches)
> > +{
> 
> return could be "bool" instead of "int" right?
> 

Yes. In new code.

> > +	u8 id = 0;
> > +
> > +	*prev_loc = CY_IGNR_TCH;
> > +
> > +		cyttsp_xdebug("IN p[%d]=%d c=%d n=%d loc=%d\n", \
> > +			id, prev_track[id], cur_trk_id, \
> > +			num_touches, *prev_loc);
> 
> Indentation problem.
> 

New code should be clean.

> > +	for (id = 0, *prev_loc = CY_IGNR_TCH;
> > +		(id < num_touches); id++) {
> > +		cyttsp_xdebug("p[%d]=%d c=%d n=%d loc=%d\n", \
> > +			id, prev_track[id], cur_trk_id, \
> > +			num_touches, *prev_loc);
> > +		if (prev_track[id] == cur_trk_id) {
> > +			*prev_loc = id;
> > +			break;
> > +		}
> > +	}
> > +	cyttsp_xdebug("OUT p[%d]=%d c=%d n=%d loc=%d\n", \
> > +		id, prev_track[id], cur_trk_id, num_touches, *prev_loc);
> > +
> > +	return ((*prev_loc < CY_NUM_TRK_ID) ? true : false);
> > +}
> > +
> > +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> > +			u8 *new_loc, u8 num_touches)
> > +{
> 
> return could be "bool" instead of "int" right?
> 

Yes. In new code.

> > +	u8 id;
> > +
> > +	for (id = 0, *new_loc = CY_IGNR_TCH;
> > +		(id < num_touches); id++) {
> > +		if (cur_trk[id] > CY_NUM_TRK_ID) {
> > +			*new_loc = id;
> > +			break;
> > +		}
> > +	}
> > +
> > +	return ((*new_loc < CY_NUM_TRK_ID) ? true : false);
> > +}
> > +
> > +/* Timer function used as dummy interrupt driver */
> > +static void cyttsp_timer(unsigned long handle)
> > +{
> > +	struct cyttsp *ts = (struct cyttsp *) handle;
> > +
> > +	cyttsp_xdebug("TTSP Device timer event\n");
> > +
> > +	/* schedule motion signal handling */
> > +	queue_work(cyttsp_ts_wq, &ts->work);
> > +
> > +	return;
> > +}
> > +
> > +
> > +
> > +/*
>
***********************************************************************
> *
> > + * ISR function. This function is general, initialized in drivers
> init
> > + * function
> > + *
>
***********************************************************************
> * */
> > +static irqreturn_t cyttsp_irq(int irq, void *handle)
> > +{
> > +	struct cyttsp *ts = (struct cyttsp *) handle;
> > +
> > +	cyttsp_xdebug("%s: Got IRQ\n", CY_I2C_NAME);
> > +
> > +	/* disable further interrupts until this interrupt is processed
> */
> > +	disable_irq_nosync(ts->client->irq);
> 
> As indicated below please use request_threaded_irq(..).
> 
> 

New code uses request_threaded_irq().

> > +
> > +	/* schedule motion signal handling */
> > +	queue_work(cyttsp_ts_wq, &ts->work);
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +/*
>
***********************************************************************
> *
> > + * Probe initialization functions
> > + *
>
***********************************************************************
> * */
> > +static int cyttsp_putbl(struct cyttsp *ts, int show,
> > +			int show_status, int show_version, int show_cid)
> > +{
> > +	int retval = CY_OK;
> > +
> > +	int num_bytes = (show_status * 3) + (show_version * 6) +
> (show_cid * 3);
> > +
> > +	if (show_cid)
> > +		num_bytes = sizeof(struct cyttsp_bootloader_data_t);
> > +	else if (show_version)
> > +		num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 3;
> > +	else
> > +		num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 9;
> > +
> > +	if (show) {
> > +		retval = i2c_smbus_read_i2c_block_data(ts->client,
> > +			CY_REG_BASE, num_bytes, (u8 *)&g_bl_data);
> > +		if (show_status) {
> > +			cyttsp_debug("BL%d: f=%02X s=%02X err=%02X
> bl=%02X%02X bld=%02X%02X\n", \
> > +				show, \
> > +				g_bl_data.bl_file, \
> > +				g_bl_data.bl_status, \
> > +				g_bl_data.bl_error, \
> > +				g_bl_data.blver_hi, g_bl_data.blver_lo,
\
> > +				g_bl_data.bld_blver_hi,
> g_bl_data.bld_blver_lo);
> > +		}
> > +		if (show_version) {
> > +			cyttsp_debug("BL%d: ttspver=0x%02X%02X
> appid=0x%02X%02X appver=0x%02X%02X\n", \
> > +				show, \
> > +				g_bl_data.ttspver_hi,
g_bl_data.ttspver_lo, \
> > +				g_bl_data.appid_hi, g_bl_data.appid_lo,
\
> > +				g_bl_data.appver_hi,
g_bl_data.appver_lo);
> > +		}
> > +		if (show_cid) {
> > +			cyttsp_debug("BL%d: cid=0x%02X%02X%02X\n", \
> > +				show, \
> > +				g_bl_data.cid_0, \
> > +				g_bl_data.cid_1, \
> > +				g_bl_data.cid_2);
> > +		}
> > +		mdelay(CY_DLY_DFLT);
> > +	}
> > +
> > +	return retval;
> > +}
> > +
> > +#ifdef CY_INCLUDE_LOAD_FILE
> 
> Could you please explain what is the use of this #define?
> 
> Are we loading any firmware? Please explain why we can't use
> request_firware(...).
> 

New code replaces included code with file based loader support.

> > +#define CY_MAX_I2C_LEN	256
> > +#define CY_MAX_TRY		10
> > +#define CY_BL_PAGE_SIZE	16
> > +#define CY_BL_NUM_PAGES	5
> > +static int cyttsp_i2c_wr_blk_data(struct i2c_client *client, u8
> command,
> > +			       u8 length, const u8 *values)
> > +{
> > +	int retval = CY_OK;
> > +
> > +	u8 dataray[CY_MAX_I2C_LEN];
> > +	u8 try;
> > +	dataray[0] = command;
> > +	if (length)
> > +		memcpy(&dataray[1], values, length);
> > +
> > +	try = CY_MAX_TRY;
> > +	do {
> > +		retval = i2c_master_send(client, dataray, length+1);
> > +		mdelay(CY_DLY_DFLT*2);
> > +	} while ((retval != length+1) && try--);
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_i2c_wr_blk_chunks(struct cyttsp *ts, u8 command,
> > +			       u8 length, const u8 *values)
> > +{
> > +	int retval = CY_OK;
> > +	int block = 1;
> > +
> > +	u8 dataray[CY_MAX_I2C_LEN];
> > +
> > +	/* first page already includes the bl page offset */
> > +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> > +		CY_BL_PAGE_SIZE+1, values);
> > +	mdelay(10);
> > +	values += CY_BL_PAGE_SIZE+1;
> > +	length -= CY_BL_PAGE_SIZE+1;
> > +
> > +	/* rem blocks require bl page offset stuffing */
> > +	while (length &&
> > +		(block < CY_BL_NUM_PAGES) &&
> > +		!(retval < CY_OK)) {
> > +		dataray[0] = CY_BL_PAGE_SIZE*block;
> > +		memcpy(&dataray[1], values,
> > +			length >= CY_BL_PAGE_SIZE ?
> > +			CY_BL_PAGE_SIZE : length);
> > +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> > +			CY_REG_BASE,
> > +			length >= CY_BL_PAGE_SIZE ?
> > +			CY_BL_PAGE_SIZE + 1 : length+1, dataray);
> > +		mdelay(10);
> > +		values += CY_BL_PAGE_SIZE;
> > +		length = length >= CY_BL_PAGE_SIZE ?
> > +			length - CY_BL_PAGE_SIZE : 0;
> > +		block++;
> > +	}
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_bootload_app(struct cyttsp *ts)
> > +{
> > +	int retval = CY_OK;
> > +	int i, tries;
> > +	u8 host_reg;
> > +
> > +	cyttsp_debug("load new firmware \n");
> > +	/* reset TTSP Device back to bootloader mode */
> > +	host_reg = CY_SOFT_RESET_MODE;
> > +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> > +		sizeof(host_reg), &host_reg);
> > +	/* wait for TTSP Device to complete reset back to bootloader */
> > +	mdelay(1000);
> > +	cyttsp_putbl(ts, 3, true, true, true);
> > +	cyttsp_debug("load file - tver=0x%02X%02X a_id=0x%02X%02X
> aver=0x%02X%02X\n", \
> > +		cyttsp_fw_tts_verh, cyttsp_fw_tts_verl, \
> > +		cyttsp_fw_app_idh, cyttsp_fw_app_idl, \
> > +		cyttsp_fw_app_verh, cyttsp_fw_app_verl);
> > +
> > +	/* download new TTSP Application to the Bootloader */
> > +	if (!(retval < CY_OK)) {
> > +		i = 0;
> > +		/* send bootload initiation command */
> > +		if (cyttsp_fw[i].Command == CY_BL_INIT_LOAD) {
> > +			g_bl_data.bl_file = 0;
> > +			g_bl_data.bl_status = 0;
> > +			g_bl_data.bl_error = 0;
> > +			retval =
i2c_smbus_write_i2c_block_data(ts->client,
> > +				CY_REG_BASE,
> > +				cyttsp_fw[i].Length,
cyttsp_fw[i].Block);
> > +			/* delay to allow bl to get ready for block
writes */
> > +			i++;
> > +			tries = 0;
> > +			cyttsp_debug("wait init f=%02X, s=%02X, e=%02X
> t=%d\n", \
> > +				g_bl_data.bl_file, g_bl_data.bl_status,
\
> > +				g_bl_data.bl_error, tries);
> > +			do {
> > +				mdelay(1000);
> > +				cyttsp_putbl(ts, 4, true, false, false);
> > +			} while (g_bl_data.bl_status != 0x10 &&
> > +				g_bl_data.bl_status != 0x11 &&
> > +				tries++ < 10);
> > +			/* send bootload firmware load blocks */
> > +			if (!(retval < CY_OK)) {
> > +				while (cyttsp_fw[i].Command ==
CY_BL_WRITE_BLK)
> {
> > +					retval =
cyttsp_i2c_wr_blk_chunks(ts,
> > +						CY_REG_BASE,
> > +						cyttsp_fw[i].Length,
> > +						cyttsp_fw[i].Block);
> > +					/* bl requires dly after blocks
*/
> > +					mdelay(100);
> > +					cyttsp_debug("BL DNLD Rec=% 3d
Len=% 3d
> Addr=%04X\n", \
> > +						cyttsp_fw[i].Record, \
> > +						cyttsp_fw[i].Length, \
> > +						cyttsp_fw[i].Address);
> > +					i++;
> > +					if (retval < CY_OK) {
> > +						cyttsp_debug("BL fail
Rec=%3d
> retval=%d\n", \
> > +
cyttsp_fw[i-1].Record, \
> > +							retval);
> > +						break;
> > +					} else {
> > +						/* reset TTSP I2C
counter */
> > +						retval =
cyttsp_i2c_wr_blk_data(ts-
> >client,
> > +							CY_REG_BASE,
> > +							0, NULL);
> > +						mdelay(10);
> > +						cyttsp_putbl(ts, 5,
> > +							true, false,
false);
> > +					}
> > +				}
> > +				if (!(retval < CY_OK)) {
> > +					while (i < cyttsp_fw_records) {
> > +						retval =
> i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> > +
cyttsp_fw[i].Length,
> > +
cyttsp_fw[i].Block);
> > +						i++;
> > +						tries = 0;
> > +						cyttsp_debug("wait init
f=%02X,
> s=%02X, e=%02X t=%d\n", \
> > +
g_bl_data.bl_file, \
> > +
g_bl_data.bl_status, \
> > +
g_bl_data.bl_error, \
> > +							tries);
> > +						do {
> > +							mdelay(1000);
> > +							cyttsp_putbl(ts,
6, true,
> false, false);
> > +						} while
(g_bl_data.bl_status !=
> 0x10 &&
> > +
g_bl_data.bl_status != 0x11
> &&
> > +							tries++ < 10);
> > +						cyttsp_putbl(ts, 7,
true, false,
> > +							false);
> > +						if (retval < CY_OK)
> > +							break;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	/* reset TTSP Device back to bootloader mode */
> > +	host_reg = CY_SOFT_RESET_MODE;
> > +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> > +		sizeof(host_reg), &host_reg);
> > +	/* wait for TTSP Device to complete reset back to bootloader */
> > +	mdelay(1000);
> > +
> > +	/* set arg2 to non-0 to activate */
> > +	retval = cyttsp_putbl(ts, 8, true, true, true);
> > +
> > +	return retval;
> > +}
> > +#else
> > +static int cyttsp_bootload_app(struct cyttsp *ts)
> > +{
> > +	cyttsp_debug("no-load new firmware \n");
> > +	return CY_OK;
> > +}
> > +#endif /* CY_INCLUDE_LOAD_FILE */
> > +
> > +
> > +static int cyttsp_power_on(struct cyttsp *ts)
> > +{
> > +	int retval = CY_OK;
> > +	u8 host_reg;
> > +	int tries;
> > +
> > +	cyttsp_debug("Power up \n");
> > +
> > +	/* check if the TTSP device has a bootloader installed */
> > +	host_reg = CY_SOFT_RESET_MODE;
> > +	retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
> > +		sizeof(host_reg), &host_reg);
> > +	tries = 0;
> > +	do {
> > +		mdelay(1000);
> > +
> > +		/* set arg2 to non-0 to activate */
> > +		retval = cyttsp_putbl(ts, 1, true, true, true);
> > +		cyttsp_info("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X
> bld=%02X%02X R=%d\n", \
> > +			101, \
> > +			g_bl_data.bl_file, g_bl_data.bl_status, \
> > +			g_bl_data.bl_error, \
> > +			g_bl_data.blver_hi, g_bl_data.blver_lo, \
> > +			g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo,
> > +			retval);
> > +		cyttsp_info("BL%d: tver=%02X%02X a_id=%02X%02X
> aver=%02X%02X\n", \
> > +			102, \
> > +			g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
> > +			g_bl_data.appid_hi, g_bl_data.appid_lo, \
> > +			g_bl_data.appver_hi, g_bl_data.appver_lo);
> > +		cyttsp_info("BL%d: c_id=%02X%02X%02X\n", \
> > +			103, \
> > +			g_bl_data.cid_0, g_bl_data.cid_1,
g_bl_data.cid_2);
> > +	} while (!(retval < CY_OK) &&
> > +		!GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
> > +		!(g_bl_data.bl_file == CY_OP_MODE + CY_LOW_PWR_MODE) &&
> > +		tries++ < 10);
> > +
> > +	/* is bootloader missing? */
> > +	if (!(retval < CY_OK)) {
> > +		cyttsp_xdebug("Ret=%d  Check if bootloader is
> missing...\n", \
> > +			retval);
> > +		if (!GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
> > +			/* skip all bl and sys info and go to op mode */
> > +			if (!(retval < CY_OK)) {
> > +				cyttsp_xdebug("Bl is missing
(ret=%d)\n", \
> > +					retval);
> > +				host_reg = CY_OP_MODE/* +
CY_LOW_PWR_MODE*/;
> > +				retval =
i2c_smbus_write_i2c_block_data(ts-
> >client, CY_REG_BASE,
> > +					sizeof(host_reg), &host_reg);
> > +				/* wait for TTSP Device to complete
switch to
> > +				 * Operational mode */
> > +				mdelay(1000);
> > +				goto bypass;
> > +			}
> > +		}
> > +	}
> > +
> > +
> > +	/* take TTSP out of bootloader mode; go to TrueTouch operational
> mode */
> > +	if (!(retval < CY_OK)) {
> > +		cyttsp_xdebug1("exit bootloader; go operational\n");
> > +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> > +			CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
> > +		tries = 0;
> > +		do {
> > +			mdelay(1000);
> > +			cyttsp_putbl(ts, 4, true, false, false);
> > +			cyttsp_info("BL%d: f=%02X s=%02X err=%02X
bl=%02X%02X
> bld=%02X%02X\n", \
> > +				104, \
> > +				g_bl_data.bl_file, g_bl_data.bl_status,
\
> > +				g_bl_data.bl_error, \
> > +				g_bl_data.blver_hi, g_bl_data.blver_lo,
\
> > +				g_bl_data.bld_blver_hi,
> g_bl_data.bld_blver_lo);
> > +		} while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
> > +			tries++ < 10);
> > +	}
> > +
> > +
> > +
> > +	if (!(retval < CY_OK) &&
> > +		cyttsp_app_load()) {
> > +		mdelay(1000);
> > +		if (CY_DIFF(g_bl_data.ttspver_hi, cyttsp_tts_verh())  ||
> > +			CY_DIFF(g_bl_data.ttspver_lo, cyttsp_tts_verl())
||
> > +			CY_DIFF(g_bl_data.appid_hi, cyttsp_app_idh())
||
> > +			CY_DIFF(g_bl_data.appid_lo, cyttsp_app_idl())
||
> > +			CY_DIFF(g_bl_data.appver_hi, cyttsp_app_verh())
||
> > +			CY_DIFF(g_bl_data.appver_lo, cyttsp_app_verl())
||
> > +			CY_DIFF(g_bl_data.cid_0, cyttsp_cid_0())  ||
> > +			CY_DIFF(g_bl_data.cid_1, cyttsp_cid_1())  ||
> > +			CY_DIFF(g_bl_data.cid_2, cyttsp_cid_2())  ||
> > +			cyttsp_force_fw_load()) {
> > +			cyttsp_debug("blttsp=0x%02X%02X
flttsp=0x%02X%02X
> force=%d\n", \
> > +				g_bl_data.ttspver_hi,
g_bl_data.ttspver_lo, \
> > +				cyttsp_tts_verh(), cyttsp_tts_verl(), \
> > +				cyttsp_force_fw_load());
> > +			cyttsp_debug("blappid=0x%02X%02X
> flappid=0x%02X%02X\n", \
> > +				g_bl_data.appid_hi, g_bl_data.appid_lo,
\
> > +				cyttsp_app_idh(), cyttsp_app_idl());
> > +			cyttsp_debug("blappver=0x%02X%02X
> flappver=0x%02X%02X\n", \
> > +				g_bl_data.appver_hi,
g_bl_data.appver_lo, \
> > +				cyttsp_app_verh(), cyttsp_app_verl());
> > +			cyttsp_debug("blcid=0x%02X%02X%02X
> flcid=0x%02X%02X%02X\n", \
> > +				g_bl_data.cid_0, \
> > +				g_bl_data.cid_1, \
> > +				g_bl_data.cid_2, \
> > +				cyttsp_cid_0(), \
> > +				cyttsp_cid_1(), \
> > +				cyttsp_cid_2());
> > +			/* enter bootloader to load new app into TTSP
Device
> */
> > +			retval = cyttsp_bootload_app(ts);
> > +			/* take TTSP device out of bootloader mode;
> > +			 * switch back to TrueTouch operational mode */
> > +			if (!(retval < CY_OK)) {
> > +				retval =
i2c_smbus_write_i2c_block_data(ts-
> >client,
> > +					CY_REG_BASE,
> > +					sizeof(bl_cmd), bl_cmd);
> > +				/* wait for TTSP Device to complete
> > +				 * switch to Operational mode */
> > +				mdelay(1000);
> > +			}
> > +		}
> > +	}
> > +
> > +bypass:
> > +	/* switch to System Information mode to read versions
> > +	 * and set interval registers */
> > +	if (!(retval < CY_OK)) {
> > +		cyttsp_debug("switch to sysinfo mode \n");
> > +		host_reg = CY_SYSINFO_MODE;
> > +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> > +			CY_REG_BASE, sizeof(host_reg), &host_reg);
> > +		/* wait for TTSP Device to complete switch to SysInfo
mode
> */
> > +		mdelay(1000);
> > +		if (!(retval < CY_OK)) {
> > +			retval =
i2c_smbus_read_i2c_block_data(ts->client,
> > +				CY_REG_BASE,
> > +				sizeof(struct cyttsp_sysinfo_data_t),
> > +				(u8 *)&g_sysinfo_data);
> > +			cyttsp_debug("SI2: hst_mode=0x%02X
mfg_cmd=0x%02X
> mfg_stat=0x%02X\n", \
> > +				g_sysinfo_data.hst_mode, \
> > +				g_sysinfo_data.mfg_cmd, \
> > +				g_sysinfo_data.mfg_stat);
> > +			cyttsp_debug("SI2: bl_ver=0x%02X%02X\n", \
> > +				g_sysinfo_data.bl_verh, \
> > +				g_sysinfo_data.bl_verl);
> > +			cyttsp_debug("SI2: sysinfo act_int=0x%02X
> tch_tmout=0x%02X lp_int=0x%02X\n", \
> > +				g_sysinfo_data.act_intrvl, \
> > +				g_sysinfo_data.tch_tmout, \
> > +				g_sysinfo_data.lp_intrvl);
> > +			cyttsp_info("SI%d: tver=%02X%02X a_id=%02X%02X
> aver=%02X%02X\n", \
> > +				102, \
> > +				g_sysinfo_data.tts_verh, \
> > +				g_sysinfo_data.tts_verl, \
> > +				g_sysinfo_data.app_idh, \
> > +				g_sysinfo_data.app_idl, \
> > +				g_sysinfo_data.app_verh, \
> > +				g_sysinfo_data.app_verl);
> > +			cyttsp_info("SI%d: c_id=%02X%02X%02X\n", \
> > +				103, \
> > +				g_sysinfo_data.cid[0], \
> > +				g_sysinfo_data.cid[1], \
> > +				g_sysinfo_data.cid[2]);
> > +			if (!(retval < CY_OK) &&
> > +				(CY_DIFF(ts->platform_data->act_intrvl,
> > +					CY_ACT_INTRVL_DFLT)  ||
> > +				CY_DIFF(ts->platform_data->tch_tmout,
> > +					CY_TCH_TMOUT_DFLT) ||
> > +				CY_DIFF(ts->platform_data->lp_intrvl,
> > +					CY_LP_INTRVL_DFLT))) {
> > +				if (!(retval < CY_OK)) {
> > +					u8
intrvl_ray[sizeof(ts->platform_data-
> >act_intrvl) +
> > +
sizeof(ts->platform_data-
> >tch_tmout) +
> > +
sizeof(ts->platform_data-
> >lp_intrvl)];
> > +					u8 i = 0;
> > +
> > +					intrvl_ray[i++] =
> > +
ts->platform_data->act_intrvl;
> > +					intrvl_ray[i++] =
> > +
ts->platform_data->tch_tmout;
> > +					intrvl_ray[i++] =
> > +
ts->platform_data->lp_intrvl;
> > +
> > +					cyttsp_debug("SI2: platinfo
> act_intrvl=0x%02X tch_tmout=0x%02X lp_intrvl=0x%02X\n", \
> > +
ts->platform_data->act_intrvl, \
> > +
ts->platform_data->tch_tmout, \
> > +
ts->platform_data->lp_intrvl);
> > +					/* set intrvl registers */
> > +					retval =
i2c_smbus_write_i2c_block_data(
> > +						ts->client,
> > +						CY_REG_ACT_INTRVL,
> > +						sizeof(intrvl_ray),
intrvl_ray);
> > +					mdelay(CY_DLY_SYSINFO);
> > +				}
> > +			}
> > +		}
> > +		/* switch back to Operational mode */
> > +		cyttsp_debug("switch back to operational mode \n");
> > +		if (!(retval < CY_OK)) {
> > +			host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
> > +			retval =
i2c_smbus_write_i2c_block_data(ts->client,
> > +				CY_REG_BASE,
> > +				sizeof(host_reg), &host_reg);
> > +			/* wait for TTSP Device to complete
> > +			 * switch to Operational mode */
> > +			mdelay(1000);
> > +		}
> > +	}
> > +	/* init gesture setup;
> > +	 * this is required even if not using gestures
> > +	 * in order to set the active distance */
> > +	if (!(retval < CY_OK)) {
> > +		u8 gesture_setup;
> > +		cyttsp_debug("init gesture setup \n");
> > +		gesture_setup = ts->platform_data->gest_set;
> > +		retval = i2c_smbus_write_i2c_block_data(ts->client,
> > +			CY_REG_GEST_SET,
> > +			sizeof(gesture_setup), &gesture_setup);
> > +		mdelay(CY_DLY_DFLT);
> > +	}
> > +
> > +	if (!(retval < CY_OK))
> > +		ts->platform_data->power_state = CY_ACTIVE_STATE;
> > +	else
> > +		ts->platform_data->power_state = CY_IDLE_STATE;
> > +
> > +	cyttsp_debug("Retval=%d Power state is %s\n", \
> > +		retval, \
> > +		ts->platform_data->power_state == CY_ACTIVE_STATE ? \
> > +		 "ACTIVE" : "IDLE");
> 
> Whole function looks scary and hard to understand. Is it possible to
> break it into the smaller
> functionality so that it becomes easy to understand.
> 

New refactored code breaks this into modules for clarity and reuse.

> > +
> > +	return retval;
> > +}
> > +
> > +/* cyttsp_initialize: Driver Initialization. This function takes
> > + * care of the following tasks:
> > + * 1. Create and register an input device with input layer
> > + * 2. Take CYTTSP device out of bootloader mode; go operational
> > + * 3. Start any timers/Work queues.  */
> > +static int cyttsp_initialize(struct i2c_client *client, struct
> cyttsp *ts)
> > +{
> > +	struct input_dev *input_device;
> > +	int error = 0;
> > +	int retval = CY_OK;
> > +	u8 id;
> > +
> > +	/* Create the input device and register it. */
> > +	input_device = input_allocate_device();
> > +	if (!input_device) {
> > +		error = -ENOMEM;
> > +		cyttsp_xdebug1("err input allocate device\n");
> > +		goto error_free_device;
> > +	}
> > +
> > +	if (!client) {
> > +		error = ~ENODEV;
> > +		cyttsp_xdebug1("err client is Null\n");
> > +		goto error_free_device;
> > +	}
> 
> Why you are checking !client here?
> 

Fixed in new code.

> > +
> > +	if (!ts) {
> > +		error = ~ENODEV;
> 
> ~? It should be -ENODEV, right?
> 

Correct. Fixed in new code.

> > +		cyttsp_xdebug1("err context is Null\n");
> > +		goto error_free_device;
> > +	}
> > +
> > +	ts->input = input_device;
> > +	input_device->name = CY_I2C_NAME;
> > +	input_device->phys = ts->phys;
> > +	input_device->dev.parent = &client->dev;
> > +
> > +	/* init the touch structures */
> > +	ts->num_prv_st_tch = CY_NTCH;
> > +	for (id = 0; id < CY_NUM_TRK_ID; id++) {
> > +		ts->act_trk[id] = CY_NTCH;
> > +		ts->prv_mt_pos[id][CY_XPOS] = 0;
> > +		ts->prv_mt_pos[id][CY_YPOS] = 0;
> > +	}
> > +
> > +	for (id = 0; id < CY_NUM_MT_TCH_ID; id++)
> > +		ts->prv_mt_tch[id] = CY_IGNR_TCH;
> > +
> > +	for (id = 0; id < CY_NUM_ST_TCH_ID; id++)
> > +		ts->prv_st_tch[id] = CY_IGNR_TCH;
> > +
> > +	set_bit(EV_SYN, input_device->evbit);
> > +	set_bit(EV_KEY, input_device->evbit);
> > +	set_bit(EV_ABS, input_device->evbit);
> > +	set_bit(BTN_TOUCH, input_device->keybit);
> > +	set_bit(BTN_2, input_device->keybit);
> 
> You need not use atomic versions. Please use __set_bit.
> 

Converted to use __set_bit() calls.

> > +	if (ts->platform_data->use_gestures)
> > +		set_bit(BTN_3, input_device->keybit);
> > +
> > +	input_set_abs_params(input_device,
> > +		ABS_X, 0, ts->platform_data->maxx, 0, 0);
> > +	input_set_abs_params(input_device,
> > +		ABS_Y, 0, ts->platform_data->maxy, 0, 0);
> > +	input_set_abs_params(input_device,
> > +		ABS_TOOL_WIDTH, 0, CY_LARGE_TOOL_WIDTH, 0 , 0);
> > +	input_set_abs_params(input_device,
> > +		ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
> > +	input_set_abs_params(input_device,
> > +		ABS_HAT0X, 0, ts->platform_data->maxx, 0, 0);
> > +	input_set_abs_params(input_device,
> > +		ABS_HAT0Y, 0, ts->platform_data->maxy, 0, 0);
> 
> Why you are using HATxx? MT should be able to satisfy all the
> requirements.
>

Code includes Single_Touch handling to support developers with older
platform trees.  Single-touch is a board configuration selection item.
 
> > +	if (ts->platform_data->use_gestures) {
> > +		input_set_abs_params(input_device,
> > +			ABS_HAT1X, 0, CY_MAXZ, 0, 0);
> > +		input_set_abs_params(input_device,
> > +			ABS_HAT1Y, 0, CY_MAXZ, 0, 0);
> > +	}
> > +	if (ts->platform_data->use_mt) {
> > +		input_set_abs_params(input_device,
> > +			ABS_MT_POSITION_X, 0, ts->platform_data->maxx,
0, 0);
> > +		input_set_abs_params(input_device,
> > +			ABS_MT_POSITION_Y, 0, ts->platform_data->maxy,
0, 0);
> > +		input_set_abs_params(input_device,
> > +			ABS_MT_TOUCH_MAJOR, 0, CY_MAXZ, 0, 0);
> > +		input_set_abs_params(input_device,
> > +			ABS_MT_WIDTH_MAJOR, 0, CY_LARGE_TOOL_WIDTH, 0,
0);
> > +		if (ts->platform_data->use_trk_id) {
> > +			input_set_abs_params(input_device,
> > +				ABS_MT_TRACKING_ID, 0, CY_NUM_TRK_ID, 0,
0);
> > +		}
> > +	}
> > +
> > +	/* set dummy key to make driver work with virtual keys */
> > +	input_set_capability(input_device, EV_KEY, KEY_PROG1);
> 
> What is virtual keys and how they are supported?
> 

By enabling programmable keys, the developer can define regions of the
touch surface that can be translated to button presses.  The regions can
be defined in the board configuration file.

> > +
> > +	cyttsp_info("%s: Register input device\n", CY_I2C_NAME);
> > +	error = input_register_device(input_device);
> > +	if (error) {
> > +		cyttsp_alert("%s: Failed to register input device\n", \
> > +			CY_I2C_NAME);
> > +		retval = error;
> > +		goto error_free_device;
> > +	}
> > +
> > +	/* Prepare our worker structure prior to setting up the
timer/ISR
> */
> > +	INIT_WORK(&ts->work, cyttsp_xy_worker);
> > +
> > +	/* Power on the chip and make sure that I/Os are set as
specified
> > +	 * in the platform */
> > +	if (ts->platform_data->init)
> > +		retval = ts->platform_data->init(client);
> > +
> > +	if (!(retval < CY_OK))
> > +		retval = cyttsp_power_on(ts);
> > +
> > +	if (retval < 0)
> > +		goto error_free_device;
> 
> Wrong.
> 
> if (!rc) {
>      rc = power_on(ts);
>      if (!rc) {
>          rc = -Exxx;
>          goto error_path;
>      }
> }
>

The new code has been reworked.
 
> > +
> > +	/* Timer or Interrupt setup */
> > +	if (ts->client->irq == 0) {
> > +		cyttsp_info("Setting up timer\n");
> > +		setup_timer(&ts->timer, cyttsp_timer, (unsigned long)
ts);
> > +		mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
> 
> Please support only one mode in the driver. Most of the time polling
> mode is used
> only during early development phase when the IRQs doesn't work, but we
> don't want to carry
> this code here.
> 
> Please remove polling mode code.
> 

We require supporting developers that have polling models.

> > +	} else {
> > +		cyttsp_info("Setting up interrupt\n");
> > +		/* request_irq() will also call enable_irq() */
> > +		error = request_irq(client->irq, cyttsp_irq,
> > +			IRQF_TRIGGER_FALLING,
> > +			client->dev.driver->name, ts);
> 
> Please use request_threaded_irq(...) with IRQF_ONESHOT flag.
>

Done in new code.
 
> > +		if (error) {
> > +			cyttsp_alert("error: could not request irq\n");
> > +			retval = error;
> > +			goto error_free_irq;
> > +		}
> > +	}
> > +
> > +	irq_cnt = 0;
> > +	irq_cnt_total = 0;
> > +	irq_err_cnt = 0;
> > +
> > +	atomic_set(&ts->irq_enabled, 1);
> > +	retval = device_create_file(&ts->client->dev,
> &dev_attr_irq_enable);
> > +	if (retval < CY_OK) {
> > +		cyttsp_alert("File device creation failed: %d\n",
retval);
> > +		retval = -ENODEV;
> > +		goto error_free_irq;
> > +	}
> > +
> > +	cyttsp_info("%s: Successful registration\n", CY_I2C_NAME);
> > +	goto success;
> > +
> > +error_free_irq:
> > +	cyttsp_alert("Error: Failed to register IRQ handler\n");
> > +	free_irq(client->irq, ts);
> > +
> > +error_free_device:
> > +	if (input_device)
> > +		input_free_device(input_device);
> > +
> > +success:
> > +	return retval;
> > +}
> > +
> > +/* I2C driver probe function */
> > +static int __devinit cyttsp_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id)
> > +{
> > +	struct cyttsp *ts;
> > +	int error;
> > +	int retval = CY_OK;
> 
> Please don't define your own error return codes. Use appropriate one
> from the kernel like say -EINVAL etc.,
> 

Error code defines eliminated.

> > +
> > +	cyttsp_info("Start Probe 1.2\n");
> 
> Please remove such debug statements. They are of no use.
> 

Custom debug statements removed.  New code uses printk() calls.

> I don't see call to i2c_check_functionality(...)
> 

Added in new code.

> > +
> > +	/* allocate and clear memory */
> > +	ts = kzalloc(sizeof(struct cyttsp), GFP_KERNEL);
> > +	if (ts == NULL) {
> > +		cyttsp_xdebug1("err kzalloc for cyttsp\n");
> 
> Please use dev_dbg or pr_debug provided by kernel only. This comment
> applies to whole driver.
> We don't need driver specific macros please.
> 

New code uses printk() calls.

> > +		retval = -ENOMEM;
> > +	}
> > +
> > +	if (!(retval < CY_OK)) {
> > +		/* register driver_data */
> > +		ts->client = client;
> > +		ts->platform_data = client->dev.platform_data;
> > +		i2c_set_clientdata(client, ts);
> > +
> > +		error = cyttsp_initialize(client, ts);
> > +		if (error) {
> > +			cyttsp_xdebug1("err cyttsp_initialize\n");
> > +			if (ts != NULL) {
> > +				/* deallocate memory */
> > +				kfree(ts);
> > +			}
> > +/*
> > +			i2c_del_driver(&cyttsp_driver);
> > +*/
> 
> Do you need this commented out code?
> 

New code has no commented out code.

> > +			retval = -ENODEV;
> > +		} else
> > +			cyttsp_openlog();
> > +	}
> > +
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +	if (!(retval < CY_OK)) {
> > +		ts->early_suspend.level =
EARLY_SUSPEND_LEVEL_BLANK_SCREEN
> + 1;
> > +		ts->early_suspend.suspend = cyttsp_early_suspend;
> > +		ts->early_suspend.resume = cyttsp_late_resume;
> > +		register_early_suspend(&ts->early_suspend);
> > +	}
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> 
> As mentioned above I want all the early suspend code to be removed.
> Explore RunTime PM framework of the kernel.
> 

Done.

> > +
> > +	cyttsp_info("Start Probe %s\n", \
> > +		(retval < CY_OK) ? "FAIL" : "PASS");
> > +
> > +	return retval;
> > +}
> > +
> > +/* Function to manage power-on resume */
> > +static int cyttsp_resume(struct i2c_client *client)
> > +{
> > +	struct cyttsp *ts;
> > +	int retval = CY_OK;
> > +
> > +	cyttsp_debug("Wake Up\n");
> > +	ts = (struct cyttsp *) i2c_get_clientdata(client);
> 
> No need of casting.
> 

Fixed.

> > +
> > +	/* re-enable the interrupt prior to wake device */
> > +	if (ts->client->irq)
> > +		enable_irq(ts->client->irq);
> > +
> > +	if (ts->platform_data->use_sleep &&
> > +		(ts->platform_data->power_state != CY_ACTIVE_STATE)) {
> > +		if (ts->platform_data->resume)
> > +			retval = ts->platform_data->resume(client);
> > +		if (!(retval < CY_OK)) {
> > +			retval =
i2c_smbus_read_i2c_block_data(ts->client,
> > +				CY_REG_BASE,
> > +				sizeof(struct cyttsp_bootloader_data_t),
> > +				(u8 *)&g_bl_data);
> > +			if (!(retval < CY_OK) &&
> > +				GET_BOOTLOADERMODE(g_bl_data.bl_status))
{
> > +				u8 tries;
> > +				retval = i2c_smbus_write_i2c_block_data(
> > +					ts->client,
> > +					CY_REG_BASE,
> > +					sizeof(bl_cmd), bl_cmd);
> > +				/* switch back to operational mode */
> > +				tries = 0;
> > +				mdelay(10);
> > +				while
(GET_BOOTLOADERMODE(g_bl_data.bl_status)
> > +					&& tries++ < 10) {
> > +					mdelay(100);
> 
> Do you really need to use mdelay(...) in the resume path? Is there any
> way you could use msleep(..)
> or say no delay at all.
>

Replaced all mdelay with msleep in new code.

> > +					cyttsp_putbl(ts, 16,
> > +						false, false, false);
> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	if (!(retval < CY_OK) &&
> > +		(GET_HSTMODE(g_bl_data.bl_file) == CY_OK)) {
> > +		ts->platform_data->power_state = CY_ACTIVE_STATE;
> > +
> > +		/* re-enable the timer after resuming */
> > +		if (ts->client->irq == 0)
> > +			mod_timer(&ts->timer, jiffies +
TOUCHSCREEN_TIMEOUT);
> > +	} else
> > +		retval = -ENODEV;
> > +
> > +	cyttsp_debug("Wake Up %s\n", \
> > +		(retval < CY_OK) ? "FAIL" : "PASS");
> > +
> > +	return retval;
> > +}
> > +
> > +
> > +/* Function to manage low power suspend */
> > +static int cyttsp_suspend(struct i2c_client *client, pm_message_t
> message)
> 
> Please put #ifdef CONFIG_PM around suspend/resume functions.
>

Done.
 
> > +{
> > +	struct cyttsp *ts;
> > +	u8 sleep_mode = CY_OK;
> > +	int retval = CY_OK;
> > +
> > +	cyttsp_debug("Enter Sleep\n");
> > +	ts = (struct cyttsp *) i2c_get_clientdata(client);
> 
> Casting from void * is not required. Please remove.
> 

Done.

> > +
> > +	/* disable worker */
> > +	if (ts->client->irq == 0)
> > +		del_timer(&ts->timer);
> > +	else
> > +		disable_irq_nosync(ts->client->irq);
> > +	retval = cancel_work_sync(&ts->work);
> > +
> > +	if (retval)
> > +		enable_irq(ts->client->irq);
> > +
> > +	if (!(retval < CY_OK)) {
> > +		if (ts->platform_data->use_sleep &&
> > +			(ts->platform_data->power_state ==
CY_ACTIVE_STATE))
> {
> > +			if (ts->platform_data->use_sleep &
> CY_USE_DEEP_SLEEP_SEL)
> > +				sleep_mode = CY_DEEP_SLEEP_MODE;
> > +			else
> > +				sleep_mode = CY_LOW_PWR_MODE;
> > +
> > +			retval =
i2c_smbus_write_i2c_block_data(ts->client,
> > +				CY_REG_BASE,
> > +				sizeof(sleep_mode), &sleep_mode);
> > +		}
> > +	}
> > +
> > +	if (!(retval < CY_OK)) {
> > +		if (sleep_mode == CY_DEEP_SLEEP_MODE)
> > +			ts->platform_data->power_state = CY_SLEEP_STATE;
> > +		else if (sleep_mode == CY_LOW_PWR_MODE)
> > +			ts->platform_data->power_state =
CY_LOW_PWR_STATE;
> > +	}
> > +
> > +	cyttsp_debug("Sleep Power state is %s\n", \
> > +		(ts->platform_data->power_state == CY_ACTIVE_STATE) ? \
> > +		"ACTIVE" : \
> > +		((ts->platform_data->power_state == CY_SLEEP_STATE) ? \
> > +		"SLEEP" : "LOW POWER"));
> > +
> > +	return retval;
> > +}
> > +
> > +/* registered in driver struct */
> > +static int __devexit cyttsp_remove(struct i2c_client *client)
> > +{
> > +	struct cyttsp *ts;
> > +	int err;
> > +
> > +	cyttsp_alert("Unregister\n");
> > +
> > +	/* clientdata registered on probe */
> > +	ts = i2c_get_clientdata(client);
> > +	device_remove_file(&ts->client->dev, &dev_attr_irq_enable);
> > +
> > +	/* Start cleaning up by removing any delayed work and the timer
> */
> > +	if (cancel_delayed_work((struct delayed_work *)&ts->work) <
> CY_OK)
> > +		cyttsp_alert("error: could not remove work from
> workqueue\n");
> > +
> > +	/* free up timer or irq */
> > +	if (ts->client->irq == 0) {
> > +		err = del_timer(&ts->timer);
> > +		if (err < CY_OK)
> > +			cyttsp_alert("error: failed to delete timer\n");
> > +	} else
> > +		free_irq(client->irq, ts);
> > +
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +	unregister_early_suspend(&ts->early_suspend);
> > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > +
> > +	/* housekeeping */
> > +	if (ts != NULL)
> > +		kfree(ts);
> > +
> > +	cyttsp_alert("Leaving\n");
> 
> I don't removal of input_dev structures.
>

New code has removal code.
 
> > +
> > +	return 0;
> > +}
> > +
> > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > +static void cyttsp_early_suspend(struct early_suspend *handler)
> > +{
> > +	struct cyttsp *ts;
> > +
> > +	ts = container_of(handler, struct cyttsp, early_suspend);
> > +	cyttsp_suspend(ts->client, PMSG_SUSPEND);
> > +}
> > +
> > +static void cyttsp_late_resume(struct early_suspend *handler)
> > +{
> > +	struct cyttsp *ts;
> > +
> > +	ts = container_of(handler, struct cyttsp, early_suspend);
> > +	cyttsp_resume(ts->client);
> > +}
> > +#endif  /* CONFIG_HAS_EARLYSUSPEND */
> > +
> > +static int cyttsp_init(void)
> > +{
> 
> __init
> 

Module_init() used in new code.

> > +	int ret;
> > +
> > +	cyttsp_info("Cypress TrueTouch(R) Standard Product\n");
> > +	cyttsp_info("I2C Touchscreen Driver (Built %s @ %s)\n", \
> > +		__DATE__, __TIME__);
> > +
> > +	cyttsp_ts_wq = create_singlethread_workqueue("cyttsp_ts_wq");
> > +	if (cyttsp_ts_wq == NULL) {
> > +		cyttsp_debug("No memory for cyttsp_ts_wq\n");
> > +		return -ENOMEM;
> > +	}
> > +
> > +	ret = i2c_add_driver(&cyttsp_driver);
> > +
> > +	return ret;
> > +}
> > +
> > +static void cyttsp_exit(void)
> > +{
> 
> __exit
> 

Module_exit() used in new code.

> > +	if (cyttsp_ts_wq)
> > +		destroy_workqueue(cyttsp_ts_wq);
> > +	return i2c_del_driver(&cyttsp_driver);
> > +}
> > +
> > +module_init(cyttsp_init);
> > +module_exit(cyttsp_exit);
> > +
> > diff --git a/include/linux/cyttsp.h b/include/linux/cyttsp.h
> > new file mode 100644
> > index 0000000..2ab1a5c
> > --- /dev/null
> > +++ b/include/linux/cyttsp.h
> > @@ -0,0 +1,649 @@
> > +/* Header file for:
> > + * Cypress TrueTouch(TM) Standard Product touchscreen drivers.
> > + * include/linux/cyttsp.h
> 
> No file paths please.
> 

Removed in new code.

> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> along
> > + * with this program; if not, write to the Free Software
Foundation,
> Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Cypress reserves the right to make changes without further
notice
> > + * to the materials described herein. Cypress does not assume any
> > + * liability arising out of the application described herein.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> > + *
> > + */
> > +
> > +
> > +#ifndef __CYTTSP_H__
> > +#define __CYTTSP_H__
> > +
> > +#include <linux/input.h>
> > +#include <linux/timer.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/kernel.h>
> > +#include <linux/delay.h>
> > +
> > +#define CYPRESS_TTSP_NAME	"cyttsp"
> > +#define CY_I2C_NAME		"cyttsp-i2c"
> > +#define CY_SPI_NAME		"cyttsp-spi"
> 
> I don't think that driver could be easily converted to fit with "spi",
> as I see i2c calls all over.
> 

New refactored code has extracted common code into a core file and added
special I2C only and SPI only files.

> > +
> > +#ifdef CY_DECLARE_GLOBALS
> > +	uint32_t cyttsp_tsdebug;
> > +	module_param_named(tsdebug, cyttsp_tsdebug, uint, 0664);
> > +	uint32_t cyttsp_tsxdebug;
> > +	module_param_named(tsxdebug, cyttsp_tsxdebug, uint, 0664);
> > +
> > +	uint32_t cyttsp_disable_touch;
> > +	module_param_named(disable_touch, cyttsp_disable_touch, uint,
> 0664);
> > +#else
> > +	extern uint32_t cyttsp_tsdebug;
> > +	extern uint32_t cyttsp_tsxdebug;
> > +	extern uint32_t cyttsp_disable_touch;
> > +#endif
> > +
> > +
> > +
> >
>
+/*********************************************************************
> *********
> > + * Global Control, Used to control the behavior of the driver
> > + */
> > +
> > +/* defines for Gen2 (Txx2xx); Gen3 (Txx3xx)
> > + * use these defines to set cyttsp_platform_data.gen in board
config
> file
> > + */
> > +#define CY_GEN2		2
> > +#define CY_GEN3		3
> > +
> > +/* define for using I2C driver
> > + */
> > +#define CY_USE_I2C_DRIVER
> > +
> > +/* defines for using SPI driver */
> > +/*
> > +#define CY_USE_SPI_DRIVER
> > + */
> > +#define CY_SPI_DFLT_SPEED_HZ		1000000
> > +#define CY_SPI_MAX_SPEED_HZ		4000000
> > +#define CY_SPI_SPEED_HZ			CY_SPI_DFLT_SPEED_HZ
> > +#define CY_SPI_BITS_PER_WORD		8
> > +#define CY_SPI_DAV			139	/* set correct gpio id
*/
> > +#define CY_SPI_BUFSIZE			512
> 
> 
> No need of these #defines unless we see driver for SPI.
> 

New code has SPI defines only in SPI file.

> > +
> > +
> > +/* define for inclusion of TTSP App Update Load File
> > + * use this define if update to the TTSP Device is desired
> > + */
> > +/*
> > +#define CY_INCLUDE_LOAD_FILE
> > +*/
> > +
> > +/* define if force new load file for bootloader load */
> > +/*
> > +#define CY_FORCE_FW_UPDATE
> > +*/
> > +
> > +/* undef for production use */
> > +/*
> > + */
> > +#define CY_USE_DEBUG
> 
> As indicated please use kernel dev_dbg/dev_xxx and pr_debug/pr_xxx
> friends.
> 

New code only uses printk() calls.

> > +
> > +/* undef for irq use; use this define in the board configuration
> file */
> > +/*
> > +#define CY_USE_TIMER
> > + */
> 
> As indicated above polling mode should be removed.
> 

Retained to support developers using polling platform models.

> > +
> > +/* undef to allow use of extra debug capability */
> > +/*
> > +#define CY_ALLOW_EXTRA_DEBUG
> > +*/
> > +
> > +/* undef to remove additional debug prints */
> > +/*
> > +#define CY_USE_EXTRA_DEBUG
> > +*/
> > +
> > +/* undef to remove additional debug prints */
> > +/*
> > +#define CY_USE_EXTRA_DEBUG1
> > + */
> > +
> > +/* undef to use operational touch timer jiffies; else use test
> jiffies */
> > +/*
> > +#define CY_USE_TIMER_DEBUG
> > + */
> > +
> > +/* define to use canned test data */
> > +/*
> > +#define CY_USE_TEST_DATA
> > + */
> > +
> > +/* define to activate power management */
> > +/*
> > +#define CY_USE_LOW_POWER
> > + */
> 
> Please see if you can use RunTime PM apis for LPM.
>

Suspend/resume code simplified in new code.
 
> > +
> > +/* define if wake on i2c addr is activated */
> > +/*
> > +#define CY_USE_DEEP_SLEEP
> > + */
> > +
> > +/* define if gesture signaling is used
> > + * and which gesture groups to use
> > + */
> > +/*
> > +#define CY_USE_GEST
> > +#define CY_USE_GEST_GRP1
> > +#define CY_USE_GEST_GRP2
> > +#define CY_USE_GEST_GRP3
> > +#define CY_USE_GEST_GRP4
> > + */
> > +/* Active distance in pixels for a gesture to be reported
> > + * if set to 0, then all gesture movements are reported
> > + */
> > +#define CY_ACT_DIST_DFLT	8
> > +#define CY_ACT_DIST			CY_ACT_DIST_DFLT
> > +
> > +/* define if MT signals are desired */
> > +/*
> > +*/
> > +#define CY_USE_MT_SIGNALS
> > +
> > +/* define if MT tracking id signals are used */
> > +/*
> > +#define CY_USE_MT_TRACK_ID
> > + */
> > +
> > +/* define if ST signals are required */
> > +/*
> > +#define CY_USE_ST_SIGNALS
> > +*/
> > +
> > +/* define to send handshake to device */
> > +/*
> > +#define CY_USE_HNDSHK
> > +*/
> > +
> > +/* define if log all raw motion signals to a sysfs file */
> > +/*
> > +#define CY_LOG_TO_FILE
> > +*/
> > +
> > +
> > +/* End of the Global Control section
> > +
>
***********************************************************************
> *******
> > + */
> > +#define CY_DIFF(m, n)		((m) != (n))
> > +
> > +#ifdef CY_LOG_TO_FILE
> > +	#define cyttsp_openlog()	/* use sysfs */
> > +#else
> > +	#define cyttsp_openlog()
> > +#endif /* CY_LOG_TO_FILE */
> > +
> > +/* see kernel.h for pr_xxx def'ns */
> > +#define cyttsp_info(f, a...)		pr_info("%s:" f,
__func__ ,
> ## a)
> > +#define cyttsp_error(f, a...)		pr_err("%s:" f,
__func__ ,
> ## a)
> > +#define cyttsp_alert(f, a...)		pr_alert("%s:" f,
__func__ ,
> ## a)
> > +
> > +#ifdef CY_USE_DEBUG
> > +	#define cyttsp_debug(f, a...)	pr_alert("%s:" f,  __func__ , ##
a)
> > +#else
> > +	#define cyttsp_debug(f, a...)	{if (cyttsp_tsdebug) \
> > +					pr_alert("%s:" f,  __func__ , ##
a); }
> > +#endif /* CY_USE_DEBUG */
> > +
> > +#ifdef CY_ALLOW_EXTRA_DEBUG
> > +#ifdef CY_USE_EXTRA_DEBUG
> > +	#define cyttsp_xdebug(f, a...)	pr_alert("%s:" f,  __func__ ,
> ## a)
> > +#else
> > +	#define cyttsp_xdebug(f, a...)	{if (cyttsp_tsxdebug) \
> > +					pr_alert("%s:" f,  __func__ , ##
a); }
> > +#endif /* CY_USE_EXTRA_DEBUG */
> > +
> > +#ifdef CY_USE_EXTRA_DEBUG1
> > +	#define cyttsp_xdebug1(f, a...)	pr_alert("%s:" f,  __func__ ,
> ## a)
> > +#else
> > +	#define cyttsp_xdebug1(f, a...)
> > +#endif /* CY_USE_EXTRA_DEBUG1 */
> > +#else
> > +	#define cyttsp_xdebug(f, a...)
> > +	#define cyttsp_xdebug1(f, a...)
> > +#endif /* CY_ALLOW_EXTRA_DEBUG */
> 
> Please remove customized debugs.
> 

Done in new code.

> > +
> > +#ifdef CY_USE_TIMER_DEBUG
> > +	#define	TOUCHSCREEN_TIMEOUT	(msecs_to_jiffies(1000))
> > +#else
> > +	#define	TOUCHSCREEN_TIMEOUT	(msecs_to_jiffies(28))
> > +#endif
> > +
> 
> 
> 
> > +/* reduce extra signals in MT only build
> > + * be careful not to lose backward compatibility for pre-MT apps
> > + */
> > +#ifdef CY_USE_ST_SIGNALS
> > +	#define CY_USE_ST	1
> > +#else
> > +	#define CY_USE_ST	0
> > +#endif /* CY_USE_ST_SIGNALS */
> > +
> > +/* rely on kernel input.h to define Multi-Touch capability */
> > +/* if input.h defines the Multi-Touch signals, then use MT */
> > +#if defined(ABS_MT_TOUCH_MAJOR) && defined(CY_USE_MT_SIGNALS)
> > +	#define CY_USE_MT	1
> > +	#define CY_MT_SYNC(input)	input_mt_sync(input)
> > +#else
> 
> I don't think we need such hacks, as latest kernel supports MT.
> 

Hacks removed from driver code.

> > +	#define CY_USE_MT	0
> > +	#define CY_MT_SYNC(input)
> > +	/* the following includes are provided to ensure a compile;
> > +	 * the code that compiles with these defines will not be
executed
> if
> > +	 * the CY_USE_MT is properly used in the platform structure init
> > +	 */
> > +	#ifndef ABS_MT_TOUCH_MAJOR
> > +	#define ABS_MT_TOUCH_MAJOR	0x30	/* touching ellipse */
> > +	#define ABS_MT_TOUCH_MINOR	0x31	/* (omit if circular) */
> > +	#define ABS_MT_WIDTH_MAJOR	0x32	/* approaching ellipse
*/
> > +	#define ABS_MT_WIDTH_MINOR	0x33	/* (omit if circular) */
> > +	#define ABS_MT_ORIENTATION	0x34	/* Ellipse orientation
*/
> > +	#define ABS_MT_POSITION_X	0x35	/* Center X ellipse
position
> */
> > +	#define ABS_MT_POSITION_Y	0x36	/* Center Y ellipse
position
> */
> > +	#define ABS_MT_TOOL_TYPE	0x37	/* Type of touching
device */
> > +	#define ABS_MT_BLOB_ID		0x38	/* Group set of pkts as
blob
> */
> > +	#endif /* ABS_MT_TOUCH_MAJOR */
> > +#endif /* ABS_MT_TOUCH_MAJOR and CY_USE_MT_SIGNALS */
> > +#if defined(ABS_MT_TRACKING_ID)  && defined(CY_USE_MT_TRACK_ID)
> > +	#define CY_USE_TRACKING_ID	1
> > +#else
> > +	#define CY_USE_TRACKING_ID	0
> > +/* define only if not defined already by system;
> > + * value based on linux kernel 2.6.30.10
> > + */
> > +#ifndef ABS_MT_TRACKING_ID
> > +	#define ABS_MT_TRACKING_ID	(ABS_MT_BLOB_ID+1)
> > +#endif
> > +#endif /* ABS_MT_TRACKING_ID */
> > +
> > +#ifdef CY_USE_DEEP_SLEEP
> > +	#define CY_USE_DEEP_SLEEP_SEL	0x80
> > +#else
> > +	#define CY_USE_DEEP_SLEEP_SEL	0x00
> > +#endif
> > +#ifdef CY_USE_LOW_POWER
> > +	#define CY_USE_SLEEP	(CY_USE_DEEP_SLEEP_SEL | 0x01)
> > +#else
> > +	#define CY_USE_SLEEP	0x00
> > +#endif /* CY_USE_LOW_POWER */
> > +
> > +#ifdef CY_USE_TEST_DATA
> > +	#define cyttsp_testdat(ray1, ray2, sizeofray) \
> > +		{ \
> > +			int i; \
> > +			u8 *up1 = (u8 *)ray1; \
> > +			u8 *up2 = (u8 *)ray2; \
> > +			for (i = 0; i < sizeofray; i++) { \
> > +				up1[i] = up2[i]; \
> > +			} \
> > +		}
> > +#else
> > +	#define cyttsp_testdat(xy, test_xy, sizeofray)
> > +#endif /* CY_USE_TEST_DATA */
> > +
> > +/* helper macros */
> > +#define GET_NUM_TOUCHES(x)		((x) & 0x0F)
> > +#define GET_TOUCH1_ID(x)		(((x) & 0xF0) >> 4)
> > +#define GET_TOUCH2_ID(x)		((x) & 0x0F)
> > +#define GET_TOUCH3_ID(x)		(((x) & 0xF0) >> 4)
> > +#define GET_TOUCH4_ID(x)		((x) & 0x0F)
> > +#define IS_LARGE_AREA(x)		(((x) & 0x10) >> 4)
> > +#define FLIP_DATA_FLAG			0x01
> > +#define REVERSE_X_FLAG			0x02
> > +#define REVERSE_Y_FLAG			0x04
> > +#define FLIP_DATA(flags)		((flags) & FLIP_DATA_FLAG)
> > +#define REVERSE_X(flags)		((flags) & REVERSE_X_FLAG)
> > +#define REVERSE_Y(flags)		((flags) & REVERSE_Y_FLAG)
> > +#define FLIP_XY(x, y)			{ \
> > +						u16 tmp; \
> > +						tmp = (x); \
> > +						(x) = (y); \
> > +						(y) = tmp; \
> > +					}
> > +#define INVERT_X(x, xmax)		((xmax) - (x))
> > +#define INVERT_Y(y, ymax)		((ymax) - (y))
> > +#define SET_HSTMODE(reg, mode)		((reg) & (mode))
> > +#define GET_HSTMODE(reg)		((reg & 0x70) >> 4)
> > +#define GET_BOOTLOADERMODE(reg)		((reg & 0x10) >> 4)
> > +
> > +/* constant definitions */
> > +/* maximum number of concurrent ST track IDs */
> > +#define CY_NUM_ST_TCH_ID		2
> > +
> > +/* maximum number of concurrent MT track IDs */
> > +#define CY_NUM_MT_TCH_ID		4
> > +
> > +/* maximum number of track IDs */
> > +#define CY_NUM_TRK_ID			16
> > +
> > +#define CY_NTCH				0	/* no touch
(lift off)
> */
> > +#define CY_TCH				1	/* active touch
(touchdown)
> */
> > +#define CY_ST_FNGR1_IDX			0
> > +#define CY_ST_FNGR2_IDX			1
> > +#define CY_MT_TCH1_IDX			0
> > +#define CY_MT_TCH2_IDX			1
> > +#define CY_MT_TCH3_IDX			2
> > +#define CY_MT_TCH4_IDX			3
> > +#define CY_XPOS				0
> > +#define CY_YPOS				1
> > +#define CY_IGNR_TCH			(-1)
> > +#define CY_SMALL_TOOL_WIDTH		10
> > +#define CY_LARGE_TOOL_WIDTH		255
> > +#define CY_REG_BASE			0x00
> > +#define CY_REG_GEST_SET			0x1E
> > +#define CY_REG_ACT_INTRVL		0x1D
> > +#define CY_REG_TCH_TMOUT		(CY_REG_ACT_INTRVL+1)
> > +#define CY_REG_LP_INTRVL		(CY_REG_TCH_TMOUT+1)
> > +#define CY_SOFT_RESET			((1 << 0))
> > +#define CY_DEEP_SLEEP			((1 << 1))
> > +#define CY_LOW_POWER			((1 << 2))
> > +#define CY_MAXZ				255
> > +#define CY_OK				0
> > +#define CY_INIT				1
> > +#define	CY_DLY_DFLT			10	/* ms */
> > +#define CY_DLY_SYSINFO			20	/* ms */
> > +#define CY_DLY_BL			300
> > +#define CY_DLY_DNLOAD			100	/* ms */
> > +#define CY_NUM_RETRY			4	/* max num touch
data read */
> > +
> > +/* handshake bit in the hst_mode reg */
> > +#define CY_HNDSHK_BIT			0x80
> > +#ifdef CY_USE_HNDSHK
> > +	#define CY_SEND_HNDSHK		1
> > +#else
> > +	#define CY_SEND_HNDSHK		0
> > +#endif
> > +
> > +/* Bootloader File 0 offset */
> > +#define CY_BL_FILE0			0x00
> > +
> > +/* Bootloader command directive */
> > +#define CY_BL_CMD			0xFF
> > +
> > +/* Bootloader Initiate Bootload */
> > +#define CY_BL_INIT_LOAD			0x38
> > +
> > +/* Bootloader Write a Block */
> > +#define CY_BL_WRITE_BLK			0x39
> > +
> > +/* Bootloader Terminate Bootload */
> > +#define CY_BL_TERMINATE			0x3B
> > +
> > +/* Bootloader Exit and Verify Checksum command */
> > +#define CY_BL_EXIT			0xA5
> > +
> > +/* Bootloader default keys */
> > +#define CY_BL_KEY0			0x00
> > +#define CY_BL_KEY1			0x01
> > +#define CY_BL_KEY2			0x02
> > +#define CY_BL_KEY3			0x03
> > +#define CY_BL_KEY4			0x04
> > +#define CY_BL_KEY5			0x05
> > +#define CY_BL_KEY6			0x06
> > +#define CY_BL_KEY7			0x07
> > +
> > +/* Active Power state scanning/processing refresh interval */
> > +#define CY_ACT_INTRVL_DFLT		0x00
> > +
> > +/* touch timeout for the Active power */
> > +#define CY_TCH_TMOUT_DFLT		0xFF
> > +
> > +/* Low Power state scanning/processing refresh interval */
> > +#define CY_LP_INTRVL_DFLT		0x0A
> > +
> > +#define CY_IDLE_STATE		0
> > +#define CY_ACTIVE_STATE		1
> > +#define CY_LOW_PWR_STATE		2
> > +#define CY_SLEEP_STATE		3
> > +
> > +/* device mode bits */
> > +#define CY_OP_MODE		0x00
> > +#define CY_SYSINFO_MODE		0x10
> > +
> > +/* power mode select bits */
> > +#define CY_SOFT_RESET_MODE		0x01	/* return to Bootloader
mode
> */
> > +#define CY_DEEP_SLEEP_MODE		0x02
> > +#define CY_LOW_PWR_MODE		0x04
> > +
> > +#define CY_NUM_KEY			8
> > +
> > +#ifdef CY_USE_GEST
> > +	#define CY_USE_GESTURES	1
> > +#else
> > +	#define CY_USE_GESTURES	0
> > +#endif /* CY_USE_GESTURE_SIGNALS */
> > +
> > +#ifdef CY_USE_GEST_GRP1
> > +	#define CY_GEST_GRP1	0x10
> > +#else
> > +	#define CY_GEST_GRP1	0x00
> > +#endif	/* CY_USE_GEST_GRP1 */
> > +#ifdef CY_USE_GEST_GRP2
> > +	#define CY_GEST_GRP2	0x20
> > +#else
> > +	#define CY_GEST_GRP2	0x00
> > +#endif	/* CY_USE_GEST_GRP2 */
> > +#ifdef CY_USE_GEST_GRP3
> > +	#define CY_GEST_GRP3	0x40
> > +#else
> > +	#define CY_GEST_GRP3	0x00
> > +#endif	/* CY_USE_GEST_GRP3 */
> > +#ifdef CY_USE_GEST_GRP4
> > +	#define CY_GEST_GRP4	0x80
> > +#else
> > +	#define CY_GEST_GRP4	0x00
> > +#endif	/* CY_USE_GEST_GRP4 */
> > +
> > +
> > +struct cyttsp_platform_data {
> > +	u32 maxx;
> > +	u32 maxy;
> > +	u32 flags;
> > +	u8 gen;
> > +	u8 use_st;
> > +	u8 use_mt;
> > +	u8 use_hndshk;
> > +	u8 use_trk_id;
> > +	u8 use_sleep;
> > +	u8 use_gestures;
> > +	u8 gest_set;
> > +	u8 act_intrvl;
> > +	u8 tch_tmout;
> > +	u8 lp_intrvl;
> > +	u8 power_state;
> > +#ifdef CY_USE_I2C_DRIVER
> > +	s32 (*init)(struct i2c_client *client);
> > +	s32 (*resume)(struct i2c_client *client);
> > +#endif
> > +#ifdef CY_USE_SPI_DRIVER
> > +	s32 (*init)(struct spi_device *spi);
> > +	s32 (*resume)(struct spi_device *spi);
> > +#endif
> > +};
> > +
> > +/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */
> > +struct cyttsp_gen3_xydata_t {
> > +	u8 hst_mode;
> > +	u8 tt_mode;
> > +	u8 tt_stat;
> > +	u16 x1 __attribute__ ((packed));
> > +	u16 y1 __attribute__ ((packed));
> > +	u8 z1;
> > +	u8 touch12_id;
> > +	u16 x2 __attribute__ ((packed));
> > +	u16 y2 __attribute__ ((packed));
> > +	u8 z2;
> > +	u8 gest_cnt;
> > +	u8 gest_id;
> > +	u16 x3 __attribute__ ((packed));
> > +	u16 y3 __attribute__ ((packed));
> > +	u8 z3;
> > +	u8 touch34_id;
> > +	u16 x4 __attribute__ ((packed));
> > +	u16 y4 __attribute__ ((packed));
> > +	u8 z4;
> > +	u8 tt_undef[3];
> > +	u8 gest_set;
> > +	u8 tt_reserved;
> > +};
> 
> Do you really need this to be exported in the header file? If possible
> move it to the .c file.
> 

This has been done in the new refactored code.

> > +
> > +/* TrueTouch Standard Product Gen2 (Txx2xx) interface definition */
> > +#define CY_GEN2_NOTOUCH		0x03	/* Both touches removed
*/
> > +#define CY_GEN2_GHOST		0x02	/* ghost */
> > +#define CY_GEN2_2TOUCH		0x03	/* 2 touch; no ghost */
> > +#define CY_GEN2_1TOUCH		0x01	/* 1 touch only */
> > +#define CY_GEN2_TOUCH2		0x01	/* 1st touch removed;
> > +						 * 2nd touch remains */
> > +struct cyttsp_gen2_xydata_t {
> > +	u8 hst_mode;
> > +	u8 tt_mode;
> > +	u8 tt_stat;
> > +	u16 x1 __attribute__ ((packed));
> > +	u16 y1 __attribute__ ((packed));
> > +	u8 z1;
> > +	u8 evnt_idx;
> > +	u16 x2 __attribute__ ((packed));
> > +	u16 y2 __attribute__ ((packed));
> > +	u8 tt_undef1;
> > +	u8 gest_cnt;
> > +	u8 gest_id;
> > +	u8 tt_undef[14];
> > +	u8 gest_set;
> > +	u8 tt_reserved;
> > +};
> > +
> > +/* TTSP System Information interface definition */
> > +struct cyttsp_sysinfo_data_t {
> > +	u8 hst_mode;
> > +	u8 mfg_cmd;
> > +	u8 mfg_stat;
> > +	u8 cid[3];
> > +	u8 tt_undef1;
> > +	u8 uid[8];
> > +	u8 bl_verh;
> > +	u8 bl_verl;
> > +	u8 tts_verh;
> > +	u8 tts_verl;
> > +	u8 app_idh;
> > +	u8 app_idl;
> > +	u8 app_verh;
> > +	u8 app_verl;
> > +	u8 tt_undef[6];
> > +	u8 act_intrvl;
> > +	u8 tch_tmout;
> > +	u8 lp_intrvl;
> > +};
> 
> Ditto.
> 
> > +
> > +/* TTSP Bootloader Register Map interface definition */
> > +#define CY_BL_CHKSUM_OK		0x01
> > +struct cyttsp_bootloader_data_t {
> > +	u8 bl_file;
> > +	u8 bl_status;
> > +	u8 bl_error;
> > +	u8 blver_hi;
> > +	u8 blver_lo;
> > +	u8 bld_blver_hi;
> > +	u8 bld_blver_lo;
> > +	u8 ttspver_hi;
> > +	u8 ttspver_lo;
> > +	u8 appid_hi;
> > +	u8 appid_lo;
> > +	u8 appver_hi;
> > +	u8 appver_lo;
> > +	u8 cid_0;
> > +	u8 cid_1;
> > +	u8 cid_2;
> > +};
> > +
> > +#define cyttsp_wake_data_t		cyttsp_gen3_xydata_t
> > +#ifdef CY_DECLARE_GLOBALS
> > +	#ifdef CY_INCLUDE_LOAD_FILE
> > +		/* this file declares:
> > +		 * firmware download block array (cyttsp_fw[]),
> > +		 * the number of command block records
(cyttsp_fw_records),
> > +		 * and the version variables
> > +		 */
> > +		#include "cyttsp_fw.h"		/* imports cyttsp_fw[]
array
> */
> > +		#define cyttsp_app_load()	1
> > +		#ifdef CY_FORCE_FW_UPDATE
> > +			#define cyttsp_force_fw_load()	1
> > +		#else
> > +			#define cyttsp_force_fw_load()	0
> > +		#endif
> > +
> > +	#else
> > +		/* the following declarations are to allow
> > +		 * some debugging capability
> > +		 */
> > +		unsigned char cyttsp_fw_tts_verh = 0x00;
> > +		unsigned char cyttsp_fw_tts_verl = 0x01;
> > +		unsigned char cyttsp_fw_app_idh = 0x02;
> > +		unsigned char cyttsp_fw_app_idl = 0x03;
> > +		unsigned char cyttsp_fw_app_verh = 0x04;
> > +		unsigned char cyttsp_fw_app_verl = 0x05;
> > +		unsigned char cyttsp_fw_cid_0 = 0x06;
> > +		unsigned char cyttsp_fw_cid_1 = 0x07;
> > +		unsigned char cyttsp_fw_cid_2 = 0x08;
> > +		#define cyttsp_app_load()	0
> > +		#define cyttsp_force_fw_load()	0
> > +	#endif
> > +	#define cyttsp_tts_verh()	cyttsp_fw_tts_verh
> > +	#define cyttsp_tts_verl()	cyttsp_fw_tts_verl
> > +	#define cyttsp_app_idh()	cyttsp_fw_app_idh
> > +	#define cyttsp_app_idl()	cyttsp_fw_app_idl
> > +	#define cyttsp_app_verh()	cyttsp_fw_app_verh
> > +	#define cyttsp_app_verl()	cyttsp_fw_app_verl
> > +	#define cyttsp_cid_0()		cyttsp_fw_cid_0
> > +	#define cyttsp_cid_1()		cyttsp_fw_cid_1
> > +	#define cyttsp_cid_2()		cyttsp_fw_cid_2
> > +	#ifdef CY_USE_TEST_DATA
> > +		static struct cyttsp_gen2_xydata_t tt_gen2_testray[] = {
> > +		{0x00}, {0x00}, {0x04},
> > +		{0x4000}, {0x8000}, {0x80},
> > +		{0x03},
> > +		{0x2000}, {0x1000}, {0x00},
> > +		{0x00},
> > +		{0x00},
> > +		{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> > +		 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
> > +		{0x00},
> > +		{0x00}
> > +		};
> > +
> > +		static struct cyttsp_gen3_xydata_t tt_gen3_testray[] = {
> > +		{0x00}, {0x00}, {0x04},
> > +		{0x4000}, {0x8000}, {0x80},
> > +		{0x12},
> > +		{0x2000}, {0x1000}, {0xA0},
> > +		{0x00}, {0x00},
> > +		{0x8000}, {0x4000}, {0xB0},
> > +		{0x34},
> > +		{0x4000}, {0x1000}, {0xC0},
> > +		{0x00, 0x00, 0x00},
> > +		{0x00},
> > +		{0x00}
> > +		};
> > +	#endif /* CY_USE_TEST_DATA */
> > +
> > +#else
> > +		extern u8 g_appload_ray[];
> > +#endif
> > +
> > +#endif /* __CYTTSP_H__ */
> 
> ---Trilok Soni
> 
> 
> --
> Sent by a consultant of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
> Forum.

Thank you Trilok for your review.



---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
  2010-07-13  7:55     ` Dmitry Torokhov
  2010-07-13  8:42       ` Trilok Soni
@ 2010-08-04 17:27       ` Kevin McNeely
  1 sibling, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-04 17:27 UTC (permalink / raw)
  To: Dmitry Torokhov, Trilok Soni
  Cc: David Brown, Fred, Samuel Ortiz, Eric Miao, Mark Brown,
	Simtec Linux Team, Arnaud Patard, Antonio Ospite, Henrik Rydberg,
	linux-input, linux-kernel, linux-i2c, khali, linux-arm-msm

Hello Dmitry,


> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Tuesday, July 13, 2010 12:56 AM
> To: Trilok Soni
> Cc: Kevin McNeely; David Brown; Fred; Samuel Ortiz; Eric Miao; Mark
> Brown; Simtec Linux Team; Arnaud Patard; Antonio Ospite; Henrik
> Rydberg; linux-input@vger.kernel.org; linux-kernel@vger.kernel.org;
> linux-i2c@vger.kernel.org; khali@linux-fr.org; linux-arm-
> msm@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c touchscreen driver init submit
> 
> On Tue, Jul 13, 2010 at 01:01:32PM +0530, Trilok Soni wrote:
> > Hi Kevin,
> >
> > Thanks for posting this driver.
> >
> > Adding Jean Delvar for i2c bits.
> >
> > On 7/13/2010 2:26 AM, Kevin McNeely wrote:
> > > From: Fred <fwk@ubuntu.linuxcertified.com>
> >
> > E-mail id looks wrong. Do you mean fwk@cypress.com?
> >
> > >
> > > This is a new touchscreen driver for the Cypress Semiconductor
> > > cyttsp family of devices.  This driver is for the i2c version
> > > of cyttsp parts.
> >
> > Please explain in commit text which exact version of the chips this
> driver is supporting.
> > It is hard to make out that from this text.
> > >
> > > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > > ---
> > >  drivers/input/touchscreen/Kconfig      |   13 +
> > >  drivers/input/touchscreen/Makefile     |    1 +
> > >  drivers/input/touchscreen/cyttsp-i2c.c | 2016
> ++++++++++++++++++++++++++++++++
> > >  include/linux/cyttsp.h                 |  649 ++++++++++
> >
> > Please move this file to include/linux/input directory.
> >
> 
> Or even keep it in drivers/input/touchscreen/
> 

The cyttsp.h file has been reduced to only information required by board
configuration files.

> >
> > >
> > > diff --git a/drivers/input/touchscreen/Kconfig
> b/drivers/input/touchscreen/Kconfig
> > > index 3b9d5e2..a7a69a0 100644
> > > --- a/drivers/input/touchscreen/Kconfig
> > > +++ b/drivers/input/touchscreen/Kconfig
> > > @@ -603,4 +603,17 @@ config TOUCHSCREEN_TPS6507X
> > >  	  To compile this driver as a module, choose M here: the
> > >  	  module will be called tps6507x_ts.
> > >
> > > +config TOUCHSCREEN_CYTTSP_I2C
> > > +	default n
> >
> > Do we need to provide this if it is no by default?
> >
> > > +	tristate "Cypress TTSP i2c touchscreen"
> > > +	depends on I2C
> > > +	help
> > > +	  Say Y here if you have a Cypress TTSP touchscreen
> > > +	  connected to your system's i2c bus.
> >
> > What is TTSP?
> >
> > > +
> > > +	  If unsure, say N.
> > > +
> > > +	  To compile this driver as a module, choose M here: the
> > > +	  module will be called cyttsp_i2c.
> > > +
> > >  endif
> >
> 
> Since there is SPI part should we prepare for the support and split
> bus-independent parts off? Are you working on SPI support?
> 

This has been done in refactored code that I will submit.
The new code has common code core file and separate I2C and SPI
specific files.  Core and I2C/SPI code will be part of next submission.

> >
> > > diff --git a/drivers/input/touchscreen/cyttsp-i2c.c
> b/drivers/input/touchscreen/cyttsp-i2c.c
> > > new file mode 100644
> > > index 0000000..8397aa1
> > > --- /dev/null
> > > +++ b/drivers/input/touchscreen/cyttsp-i2c.c
> > > @@ -0,0 +1,2016 @@
> > > +/* Source for:
> > > + * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
> > > + * drivers/input/touchscreen/cyttsp-i2c.c
> >
> > No file paths please. Already commented on it by Christoph.
> >
> > > + *
> > > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > > + *
> > > + * This program is free software; you can redistribute it and/or
> > > + * modify it under the terms of the GNU General Public License
> > > + * version 2, and only version 2, as published by the
> > > + * Free Software Foundation.
> > > + *
> > > + * This program is distributed in the hope that it will be
useful,
> > > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > > + * GNU General Public License for more details.
> > > + *
> > > + * You should have received a copy of the GNU General Public
> License along
> > > + * with this program; if not, write to the Free Software
> Foundation, Inc.,
> > > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > > + *
> > > + * Cypress reserves the right to make changes without further
> notice
> > > + * to the materials described herein. Cypress does not assume any
> > > + * liability arising out of the application described herein.
> > > + *
> > > + * Contact Cypress Semiconductor at www.cypress.com
> >
> > I would like Dmitry to comment on it. Dmitry?
> >
> 
> Not a lwayer but I do not really see an issue here. It is still GPL
and
> they as copyright holders obviously can modify the code. What exactly
> troubles you here?
> 
> 

This paragraph has been removed from headers.


> > > + *
> > > + */
> > > +
> > > +#include <linux/delay.h>
> > > +#include <linux/init.h>
> > > +#include <linux/module.h>
> > > +#include <linux/i2c.h>
> > > +#include <linux/input.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/gpio.h>
> > > +#include <linux/irq.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/timer.h>
> > > +#include <linux/workqueue.h>
> > > +#include <linux/byteorder/generic.h>
> > > +#include <linux/bitops.h>
> > > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > > +#include <linux/earlysuspend.h>
> > > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> >
> > We don't have early suspend support yet into the mainline kernel.
> Please remove this code from the driver.
> >
> > > +
> > > +#define CY_DECLARE_GLOBALS
> >
> > Could you please explain what it does?
> >
> > > +
> > > +#include <linux/cyttsp.h>
> > > +
> > > +uint32_t cyttsp_tsdebug1 = 0xff;
> > > +module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
> > > +
> > > +/* CY TTSP I2C Driver private data */
> > > +struct cyttsp {
> > > +	struct i2c_client *client;
> > > +	struct input_dev *input;
> > > +	struct work_struct work;
> > > +	struct timer_list timer;
> > > +	struct mutex mutex;
> > > +	char phys[32];
> > > +	struct cyttsp_platform_data *platform_data;
> > > +	u8 num_prv_st_tch;
> > > +	u16 act_trk[CY_NUM_TRK_ID];
> > > +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> > > +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> > > +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> > > +	atomic_t irq_enabled;
> > > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > > +	struct early_suspend early_suspend;
> > > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > > +};
> > > +static u8 irq_cnt;		/* comparison counter with
register valuw
> */
> >
> > s/valuw/value
> >
> > > +static u32 irq_cnt_total;	/* total interrupts */
> > > +static u32 irq_err_cnt;		/* count number of touch
interrupts
> with err */
> > > +#define CY_IRQ_CNT_MASK	0x000000FF	/* mapped for sizeof
count in
> reg */
> > > +#define CY_IRQ_CNT_REG	0x00		/* tt_undef[0]=reg 0x1B
-
> Gen3 only */
> > > +
> > > +#ifdef CONFIG_HAS_EARLYSUSPEND
> > > +static void cyttsp_early_suspend(struct early_suspend *handler);
> > > +static void cyttsp_late_resume(struct early_suspend *handler);
> > > +#endif /* CONFIG_HAS_EARLYSUSPEND */
> > > +
> > > +static struct workqueue_struct *cyttsp_ts_wq;
> >
> > Why there are so many global variables lying around?
> >
> > > +
> > > +
> > > +/*
>
***********************************************************************
> *****
> > > + * Prototypes for static functions
> > > + *
>
***********************************************************************
> *** */
> > > +static void cyttsp_xy_worker(struct work_struct *work);
> > > +static irqreturn_t cyttsp_irq(int irq, void *handle);
> > > +static int cyttsp_inlist(u16 prev_track[],
> > > +			u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
> > > +static int cyttsp_next_avail_inlist(u16 cur_trk[],
> > > +			u8 *new_loc, u8 num_touches);
> > > +static int cyttsp_putbl(struct cyttsp *ts, int show,
> > > +			int show_status, int show_version, int
show_cid);
> > > +static int __devinit cyttsp_probe(struct i2c_client *client,
> > > +			const struct i2c_device_id *id);
> > > +static int __devexit cyttsp_remove(struct i2c_client *client);
> > > +static int cyttsp_resume(struct i2c_client *client);
> > > +static int cyttsp_suspend(struct i2c_client *client, pm_message_t
> message);
> >
> > Please re-order the functions in the driver such a way so that you
> don't need have these prototypes here.
> >
> > > +
> > > +/* Static variables */
> > > +static struct cyttsp_gen3_xydata_t g_xy_data;
> > > +static struct cyttsp_bootloader_data_t g_bl_data;
> > > +static struct cyttsp_sysinfo_data_t g_sysinfo_data;
> >
> > again globals?
> >
> > > +static const struct i2c_device_id cyttsp_id[] = {
> > > +	{ CY_I2C_NAME, 0 },  { }
> >
> > Why dont you put ,{} at the next line.
> >
> > > +};
> >
> > You should not put driver name above, but it should be something
like
> real chip name.
> >
> > Say cy8ctXXX.
> >
> > > +static u8 bl_cmd[] = {
> > > +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> > > +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> > > +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> > > +	CY_BL_KEY6, CY_BL_KEY7};
> >
> > and what these keys does?
> >
> > > +
> > > +MODULE_DEVICE_TABLE(i2c, cyttsp_id);
> >
> > Why it is not with cyttsp_id above?
> >
> > > +
> > > +static struct i2c_driver cyttsp_driver = {
> > > +	.driver = {
> > > +		.name = CY_I2C_NAME,
> > > +		.owner = THIS_MODULE,
> > > +	},
> > > +	.probe = cyttsp_probe,
> > > +	.remove = __devexit_p(cyttsp_remove),
> > > +	.suspend = cyttsp_suspend,
> > > +	.resume = cyttsp_resume,
> > > +	.id_table = cyttsp_id,
> > > +};
> > > +
> > > +MODULE_LICENSE("GPL");
> > > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen
> driver");
> > > +MODULE_AUTHOR("Cypress");
> >
> > MODULE_ALIAS?
> >
> > > +
> > > +static ssize_t cyttsp_irq_status(struct device *dev,
> > > +				struct device_attribute *attr, char
*buf)
> > > +{
> > > +	struct i2c_client *client = container_of(dev, struct i2c_client,
> dev);
> > > +	struct cyttsp *ts = i2c_get_clientdata(client);
> > > +	return sprintf(buf, "%u\n", atomic_read(&ts->irq_enabled));
> > > +}
> > > +
> > > +static ssize_t cyttsp_irq_enable(struct device *dev,
> > > +				struct device_attribute *attr,
> > > +				const char *buf, size_t size)
> > > +{
> > > +	struct i2c_client *client = container_of(dev, struct i2c_client,
> dev);
> > > +	struct cyttsp *ts = i2c_get_clientdata(client);
> > > +	int err = 0;
> > > +	unsigned long value;
> > > +
> > > +	if (size > 2)
> > > +		return -EINVAL;
> > > +
> > > +	err = strict_strtoul(buf, 10, &value);
> > > +	if (err != 0)
> > > +		return err;
> > > +
> > > +	switch (value) {
> > > +	case 0:
> > > +		if (atomic_cmpxchg(&ts->irq_enabled, 1, 0)) {
> > > +			pr_info("touch irq disabled!\n");
> > > +			disable_irq_nosync(ts->client->irq);
> 
> I do not believe that this achieves what you want.., You may
reschedule
> between cmpxchg and disable_irq_nosync().
> 

This code has been removed from new code to be submitted.

> 
> Haven't looked any further yet...
> 
> --
> Dmitry

Thank you Dmitry for your review.



---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
       [not found] <Kevin McNeely <kev@cypress.com>
  2010-07-12 20:56 ` [PATCH] i2c: cyttsp i2c touchscreen driver init submit Kevin McNeely
@ 2010-08-05 18:12 ` Kevin McNeely
  2010-08-05 20:45   ` Trilok Soni
                     ` (2 more replies)
  2010-11-09 18:25 ` [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
                   ` (11 subsequent siblings)
  13 siblings, 3 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-05 18:12 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Fred, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Ben Dooks, Simtec Linux Team,
	Todd Fischer, Arnaud Patard, Sascha Hauer, Henrik Rydberg,
	linux-input, linux-kernel

From: Fred <fwk@ubuntu.linuxcertified.com>

This is a new touchscreen driver for the Cypress Semiconductor
cyttsp family of devices.  This updated driver is for both the i2c and spi
versions of the devices. The driver code consists of common core code for
both i2c and spi driver.  This submission is in response to review comments
from the initial submission.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Kconfig            |   33 +
 drivers/input/touchscreen/Makefile           |    3 +
 drivers/input/touchscreen/cyttsp_board-xxx.c |  110 ++
 drivers/input/touchscreen/cyttsp_core.c      | 1778 ++++++++++++++++++++++++++
 drivers/input/touchscreen/cyttsp_core.h      |   49 +
 drivers/input/touchscreen/cyttsp_i2c.c       |  183 +++
 drivers/input/touchscreen/cyttsp_spi.c       |  339 +++++
 include/linux/cyttsp.h                       |  104 ++
 8 files changed, 2599 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_board-xxx.c
 create mode 100755 drivers/input/touchscreen/cyttsp_core.c
 create mode 100755 drivers/input/touchscreen/cyttsp_core.h
 create mode 100755 drivers/input/touchscreen/cyttsp_i2c.c
 create mode 100755 drivers/input/touchscreen/cyttsp_spi.c
 create mode 100755 include/linux/cyttsp.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 3b9d5e2..b923379 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -603,4 +603,37 @@ config TOUCHSCREEN_TPS6507X
 	  To compile this driver as a module, choose M here: the
 	  module will be called tps6507x_ts.
 
+config TOUCHSCREEN_CYTTSP_I2C
+	default n
+	tristate "Cypress TTSP i2c touchscreen"
+	depends on I2C
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system's i2c bus.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_i2c.
+
+config TOUCHSCREEN_CYTTSP_SPI
+	default n
+	tristate "Cypress TTSP spi touchscreen"
+	depends on SPI_MASTER
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system's spi bus.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_spi.
+
+config TOUCHSCREEN_CYTTSP_CORE
+	default y
+	bool "Cypress TTSP touchscreen core"
+	depends on TOUCHSCREEN_CYTTSP_I2C || TOUCHSCREEN_CYTTSP_SPI
+	help
+	  Always activated for Cypress TTSP touchscreen
+
 endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 497964a..b3bdb09 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -47,3 +47,6 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)	+= mainstone-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE)	+= zylonite-wm97xx.o
 obj-$(CONFIG_TOUCHSCREEN_W90X900)	+= w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)	+= tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)	+= cyttsp_spi.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp_i2c.o
diff --git a/drivers/input/touchscreen/cyttsp_board-xxx.c b/drivers/input/touchscreen/cyttsp_board-xxx.c
new file mode 100644
index 0000000..cda08c8
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_board-xxx.c
@@ -0,0 +1,110 @@
+#include <linux/cyttsp.h>
+#define CY_USE_MT		/* undef for ST only */
+#define TS_GPIO_IRQ	150
+
+static int cyttsp_init(int on)
+{
+	if (on) {
+		/* add any special code to initialize any required system hw
+		 * such as regulators or gpio pins
+		 */
+		int rc;
+		pr_info(" %s: in cyttsp_platform_init \n", __func__);
+
+	 	rc = gpio_tlmm_config(GPIO_CFG(TS_GPIO_IRQ, 0, GPIO_INPUT,
+		                GPIO_PULL_UP, GPIO_6MA), GPIO_ENABLE);
+		if (rc)
+		        printk(KERN_ALERT "%s: Could not configure gpio %d\n",
+		                        __func__, TS_GPIO_IRQ);
+
+		rc = gpio_request(TS_GPIO_IRQ, "ts_irq");
+		if (rc)
+		        pr_err("%s: unable to request gpio %d (%d)\n",
+		                        __func__, TS_GPIO_IRQ, rc);
+	} else {
+		gpio_free(TS_GPIO_IRQ);
+	}
+	return 0;
+}
+
+static int cyttsp_wakeup(void)
+{
+	return 0;
+}
+
+static struct cyttsp_platform_data cypress_ttsp_platform_data = {
+	.wakeup = cyttsp_wakeup,
+	.init = cyttsp_init,
+#ifdef CY_USE_MT
+	.mt_sync = input_mt_sync,
+#endif
+	.maxx = 479,
+	.maxy = 799,
+	.flags = 0,
+	.gen = CY_GEN3,
+	.use_st = 0,
+	.use_mt = 1,
+	.use_trk_id = 0,
+	.use_hndshk = 1,
+	.use_timer = 0,
+	.use_sleep = 1,
+	.use_gestures = 0,
+	.use_load_file = 0,
+	.use_force_fw_update = 1,
+	.use_virtual_keys = 1,
+	/* activate up to 4 groups
+	 * and set active distance
+	 */
+	.gest_set = CY_GEST_GRP_NONE | CY_ACT_DIST,
+	/* change act_intrvl to customize the Active power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.act_intrvl = CY_ACT_INTRVL_DFLT,
+	/* change tch_tmout to customize the touch timeout for the
+	 * Active power state for Operating mode
+	 */
+	.tch_tmout = CY_TCH_TMOUT_DFLT,
+	/* change lp_intrvl to customize the Low Power power state
+	 * scanning/processing refresh interval for Operating mode
+	 */
+	.lp_intrvl = CY_LP_INTRVL_DFLT,
+	.name = CY_I2C_NAME,
+	.irq_gpio = TS_GPIO_IRQ,
+};
+
+#ifdef USE_I2C
+static struct i2c_board_info cyttsp_info[] __initdata = {
+	{
+		I2C_BOARD_INFO(CY_I2C_NAME, 0x24),
+		.platform_data = &cypress_ttsp_platform_data,
+		.irq = MSM_GPIO_TO_INT(TS_GPIO_IRQ),
+	},
+};
+
+static void __init xxx_init(void)
+	i2c_register_board_info(0, cyttsp_info,
+			ARRAY_SIZE(cyttsp_info));
+#else // USE_SPI
+static struct spi_board_info xxx_cyttsp_spi_board_info[] __initdata = {
+	{
+		.modalias = CY_SPI_NAME,
+		.platform_data  = &cypress_ttsp_platform_data,
+		.irq = TS_GPIO_IRQ,
+		.max_speed_hz   = 1000000,
+		.bus_num = 4,
+		.chip_select = 0,
+		.mode = SPI_MODE_0,
+	},
+};
+
+#endif
+
+static void __init xxx_cyttsp_init(void)
+{
+	printk(KERN_INFO "irq = %d\n", xxx_cyttsp_spi_board_info[0].irq);
+	spi_register_board_info(xxx_cyttsp_spi_board_info,
+			ARRAY_SIZE(xxx_cyttsp_spi_board_info));
+}
+
+#endif
+
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
new file mode 100755
index 0000000..95019e9
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,1778 @@
+/* Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx2xx and Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST241
+ * CY8CTMG240
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/byteorder/generic.h>
+#include <linux/bitops.h>
+#include <linux/cyttsp.h>
+#include <linux/ctype.h>
+#include "cyttsp_core.h"
+
+#define DBG(x)
+
+/* rely on kernel input.h to define Multi-Touch capability */
+#ifndef ABS_MT_TRACKING_ID
+/* define only if not defined already by system; */
+/* value based on linux kernel 2.6.30.10 */
+#define ABS_MT_TRACKING_ID (ABS_MT_BLOB_ID + 1)
+#endif /* ABS_MT_TRACKING_ID */
+
+#define	TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(28))
+/* Bootloader File 0 offset */
+#define CY_BL_FILE0       0x00
+/* Bootloader command directive */
+#define CY_BL_CMD         0xFF
+/* Bootloader Enter Loader mode */
+#define CY_BL_ENTER       0x38
+/* Bootloader Write a Block */
+#define CY_BL_WRITE_BLK   0x39
+/* Bootloader Terminate Loader mode */
+#define CY_BL_TERMINATE   0x3B
+/* Bootloader Exit and Verify Checksum command */
+#define CY_BL_EXIT        0xA5
+/* Bootloader default keys */
+#define CY_BL_KEY0 0
+#define CY_BL_KEY1 1
+#define CY_BL_KEY2 2
+#define CY_BL_KEY3 3
+#define CY_BL_KEY4 4
+#define CY_BL_KEY5 5
+#define CY_BL_KEY6 6
+#define CY_BL_KEY7 7
+
+#define CY_DIFF(m, n)               ((m) != (n))
+#define GET_NUM_TOUCHES(x)          ((x) & 0x0F)
+#define GET_TOUCH1_ID(x)            (((x) & 0xF0) >> 4)
+#define GET_TOUCH2_ID(x)            ((x) & 0x0F)
+#define GET_TOUCH3_ID(x)            (((x) & 0xF0) >> 4)
+#define GET_TOUCH4_ID(x)            ((x) & 0x0F)
+#define IS_LARGE_AREA(x)            (((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x)               ((x) & 0x20)
+#define FLIP_DATA_FLAG              0x01
+#define REVERSE_X_FLAG              0x02
+#define REVERSE_Y_FLAG              0x04
+#define FLIP_DATA(flags)            ((flags) & FLIP_DATA_FLAG)
+#define REVERSE_X(flags)            ((flags) & REVERSE_X_FLAG)
+#define REVERSE_Y(flags)            ((flags) & REVERSE_Y_FLAG)
+#define FLIP_XY(x, y)      {typeof(x) tmp; tmp = (x); (x) = (y); (y) = tmp; }
+#define INVERT_X(x, xmax)           ((xmax) - (x))
+#define INVERT_Y(y, ymax)           ((ymax) - (y))
+#define SET_HSTMODE(reg, mode)      ((reg) & (mode))
+#define GET_HSTMODE(reg)            ((reg & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)     ((reg & 0x10) >> 4)
+
+/* maximum number of concurrent ST track IDs */
+#define CY_NUM_ST_TCH_ID            2
+/* maximum number of concurrent MT track IDs */
+#define CY_NUM_MT_TCH_ID            4
+/* maximum number of track IDs */
+#define CY_NUM_TRK_ID               16
+
+#define CY_NTCH                     0 /* lift off */
+#define CY_TCH                      1 /* touch down */
+#define CY_ST_FNGR1_IDX             0
+#define CY_ST_FNGR2_IDX             1
+#define CY_MT_TCH1_IDX              0
+#define CY_MT_TCH2_IDX              1
+#define CY_MT_TCH3_IDX              2
+#define CY_MT_TCH4_IDX              3
+#define CY_XPOS                     0
+#define CY_YPOS                     1
+#define CY_IGNR_TCH               (-1)
+#define CY_SMALL_TOOL_WIDTH         10
+#define CY_LARGE_TOOL_WIDTH         255
+#define CY_REG_BASE                 0x00
+#define CY_REG_GEST_SET             0x1E
+#define CY_REG_ACT_INTRVL           0x1D
+#define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
+#define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
+#define CY_SOFT_RESET               (1 << 0)
+#define CY_DEEP_SLEEP               (1 << 1)
+#define CY_LOW_POWER                (1 << 2)
+#define CY_MAXZ                     255
+#define CY_INIT                     1
+#define CY_DELAY_DFLT               10 /* ms */
+#define CY_DELAY_SYSINFO            20 /* ms */
+#define CY_DELAY_BL                 300
+#define CY_DELAY_DNLOAD             100 /* ms */
+#define CY_HNDSHK_BIT               0x80
+#define CY_NUM_RETRY                4 /* max number of retries for read ops */
+/* device mode bits */
+#define CY_OPERATE_MODE             0x00
+#define CY_SYSINFO_MODE             0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE          0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE          0x02
+#define CY_LOW_POWER_MODE           0x04
+#define CY_NUM_KEY                  8
+
+/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */
+struct cyttsp_xydata {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	u16 x1 __attribute__ ((packed));
+	u16 y1 __attribute__ ((packed));
+	u8 z1;
+	u8 touch12_id;
+	u16 x2 __attribute__ ((packed));
+	u16 y2 __attribute__ ((packed));
+	u8 z2;
+	u8 gest_cnt;
+	u8 gest_id;
+	u16 x3 __attribute__ ((packed));
+	u16 y3 __attribute__ ((packed));
+	u8 z3;
+	u8 touch34_id;
+	u16 x4 __attribute__ ((packed));
+	u16 y4 __attribute__ ((packed));
+	u8 z4;
+	u8 tt_undef[3];
+	u8 gest_set;
+	u8 tt_reserved;
+};
+
+struct cyttsp_xydata_gen2 {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	u16 x1 __attribute__ ((packed));
+	u16 y1 __attribute__ ((packed));
+	u8 z1;
+	u8 evnt_idx;
+	u16 x2 __attribute__ ((packed));
+	u16 y2 __attribute__ ((packed));
+	u8 tt_undef1;
+	u8 gest_cnt;
+	u8 gest_id;
+	u8 tt_undef[14];
+	u8 gest_set;
+	u8 tt_reserved;
+};
+
+/* TrueTouch Standard Product Gen2 (Txx2xx) interface definition */
+enum cyttsp_gen2_std {
+	CY_GEN2_NOTOUCH = 0x03, /* Both touches removed */
+	CY_GEN2_GHOST =   0x02, /* ghost */
+	CY_GEN2_2TOUCH =  0x03, /* 2 touch; no ghost */
+	CY_GEN2_1TOUCH =  0x01, /* 1 touch only */
+	CY_GEN2_TOUCH2 =  0x01, /* 1st touch removed; 2nd touch remains */
+};
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[6];
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+#define cyttsp_wake_data cyttsp_xydata
+
+struct cyttsp {
+	struct device *pdev;
+	int irq;
+	struct input_dev *input;
+	struct work_struct work;
+	struct timer_list timer;
+	struct mutex mutex;
+	char phys[32];
+	struct cyttsp_platform_data *platform_data;
+	struct cyttsp_bootloader_data bl_data;
+	struct cyttsp_sysinfo_data sysinfo_data;
+	u8 num_prv_st_tch;
+	u16 act_trk[CY_NUM_TRK_ID];
+	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
+	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
+	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
+	struct cyttsp_bus_ops *bus_ops;
+	unsigned fw_loader_mode:1;
+	unsigned suspended:1;
+};
+
+struct cyttsp_track_data {
+	u8 prv_tch;
+	u8 cur_tch;
+	u16 tmp_trk[CY_NUM_MT_TCH_ID];
+	u16 snd_trk[CY_NUM_MT_TCH_ID];
+	u16 cur_trk[CY_NUM_TRK_ID];
+	u16 cur_st_tch[CY_NUM_ST_TCH_ID];
+	u16 cur_mt_tch[CY_NUM_MT_TCH_ID];
+	/* if NOT CY_USE_TRACKING_ID then only */
+	/* uses CY_NUM_MT_TCH_ID positions */
+	u16 cur_mt_pos[CY_NUM_TRK_ID][2];
+	/* if NOT CY_USE_TRACKING_ID then only */
+	/* uses CY_NUM_MT_TCH_ID positions */
+	u8 cur_mt_z[CY_NUM_TRK_ID];
+	u8 tool_width;
+	u16 st_x1;
+	u16 st_y1;
+	u8 st_z1;
+	u16 st_x2;
+	u16 st_y2;
+	u8 st_z2;
+};
+
+static const u8 bl_cmd[] = {
+	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
+	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
+	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
+	CY_BL_KEY6, CY_BL_KEY7
+};
+
+#define LOCK(m) do { \
+	DBG(printk(KERN_INFO "%s: lock\n", __func__);) \
+	mutex_lock(&(m)); \
+} while (0);
+
+#define UNLOCK(m) do { \
+	DBG(printk(KERN_INFO "%s: unlock\n", __func__);) \
+	mutex_unlock(&(m)); \
+} while (0);
+
+DBG(
+static void print_data_block(const char *func, u8 command,
+			u8 length, void *data)
+{
+	char buf[1024];
+	unsigned buf_len = sizeof(buf);
+	char *p = buf;
+	int i;
+	int l;
+
+	l = snprintf(p, buf_len, "cmd 0x%x: ", command);
+	buf_len -= l;
+	p += l;
+	for (i = 0; i < length && buf_len; i++, p += l, buf_len -= l)
+		l = snprintf(p, buf_len, "%02x ", *((char *)data + i));
+	printk(KERN_DEBUG "%s: %s\n", func, buf);
+})
+
+static u8 ttsp_convert_gen2(u8 cur_tch, struct cyttsp_xydata *pxy_data)
+{
+	struct cyttsp_xydata_gen2 *pxy_data_gen2;
+	pxy_data_gen2 = (struct cyttsp_xydata_gen2 *)(pxy_data);
+
+	if (pxy_data_gen2->evnt_idx == CY_GEN2_NOTOUCH) {
+		cur_tch = 0;
+	} else if (cur_tch == CY_GEN2_GHOST) {
+		cur_tch = 0;
+	} else if (cur_tch == CY_GEN2_2TOUCH) {
+		/* stuff artificial track ID1 and ID2 */
+		pxy_data->touch12_id = 0x12;
+		pxy_data->z1 = CY_MAXZ;
+		pxy_data->z2 = CY_MAXZ;
+		cur_tch--; /* 2 touches */
+	} else if (cur_tch == CY_GEN2_1TOUCH) {
+		/* stuff artificial track ID1 and ID2 */
+		pxy_data->touch12_id = 0x12;
+		pxy_data->z1 = CY_MAXZ;
+		pxy_data->z2 = CY_NTCH;
+		if (pxy_data_gen2->evnt_idx == CY_GEN2_TOUCH2) {
+			/* push touch 2 data into touch1
+			 * (first finger up; second finger down) */
+			/* stuff artificial track ID1 for touch2 info */
+			pxy_data->touch12_id = 0x20;
+			/* stuff touch 1 with touch 2 coordinate data */
+			pxy_data->x1 = pxy_data->x2;
+			pxy_data->y1 = pxy_data->y2;
+		}
+	} else {
+		cur_tch = 0;
+	}
+	return cur_tch;
+}
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int rc;
+	int tries;
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	if (!buf || !length) {
+		printk(KERN_ERR "%s: Error, buf:%s len:%u\n",
+				__func__, !buf ? "NULL" : "OK", length);
+		return -EIO;
+	}
+
+	for (tries = 0, rc = 1; tries < CY_NUM_RETRY && rc; tries++)
+		rc = ts->bus_ops->read(ts->bus_ops, command, length, buf);
+
+	if (rc < 0)
+		printk(KERN_ERR "%s: error %d\n", __func__, rc);
+	DBG(print_data_block(__func__, command, length, buf);)
+	return rc;
+}
+
+static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int rc;
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	if (!buf || !length) {
+		printk(KERN_ERR "%s: Error, buf:%s len:%u\n",
+				__func__, !buf ? "NULL" : "OK", length);
+		return -EIO;
+	}
+	rc = ts->bus_ops->write(ts->bus_ops, command, length, buf);
+	if (rc < 0)
+		printk(KERN_ERR "%s: error %d\n", __func__, rc);
+	DBG(print_data_block(__func__, command, length, buf);)
+	return rc;
+}
+
+static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
+{
+	int rc;
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	if (!buf) {
+		printk(KERN_ERR "%s: Error, buf:%s\n",
+				__func__, !buf ? "NULL" : "OK");
+		return -EIO;
+	}
+	rc = ts->bus_ops->ext(ts->bus_ops, buf);
+	if (rc < 0)
+		printk(KERN_ERR "%s: error %d\n", __func__, rc);
+	return rc;
+}
+
+static bool cyttsp_inlist(u16 prev_track[], u8 cur_trk_id, u8 *prev_loc,
+	u8 num_touches)
+{
+	u8 id = 0;
+
+	DBG(printk(KERN_INFO"%s: IN p[%d]=%d c=%d n=%d loc=%d\n",
+		__func__, id, prev_track[id], cur_trk_id,
+		num_touches, *prev_loc);)
+
+	for (*prev_loc = CY_IGNR_TCH; id < num_touches; id++) {
+		DBG(printk(KERN_INFO"%s: p[%d]=%d c=%d n=%d loc=%d\n",
+			__func__, id, prev_track[id], cur_trk_id,
+				num_touches, *prev_loc);)
+		if (prev_track[id] == cur_trk_id) {
+			*prev_loc = id;
+			break;
+		}
+	}
+	DBG(printk(KERN_INFO"%s: OUT p[%d]=%d c=%d n=%d loc=%d\n", __func__,
+		id, prev_track[id], cur_trk_id, num_touches, *prev_loc);)
+
+	return *prev_loc < CY_NUM_TRK_ID;
+}
+
+static bool cyttsp_next_avail_inlist(u16 cur_trk[], u8 *new_loc,
+	u8 num_touches)
+{
+	u8 id = 0;
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	for (*new_loc = CY_IGNR_TCH; id < num_touches; id++) {
+		if (cur_trk[id] > CY_NUM_TRK_ID) {
+			*new_loc = id;
+			break;
+		}
+	}
+	return *new_loc < CY_NUM_TRK_ID;
+}
+
+/* ************************************************************************
+ * The cyttsp_xy_worker function reads the XY coordinates and sends them to
+ * the input layer.  It is scheduled from the interrupt (or timer).
+ * *************************************************************************/
+void handle_single_touch(struct cyttsp_xydata *xy, struct cyttsp_track_data *t,
+			 struct cyttsp *ts)
+{
+	u8 id;
+	u8 use_trk_id = ts->platform_data->use_trk_id;
+
+	DBG(printk(KERN_INFO"%s: ST STEP 0 - ST1 ID=%d  ST2 ID=%d\n",
+		__func__, t->cur_st_tch[CY_ST_FNGR1_IDX],
+		t->cur_st_tch[CY_ST_FNGR2_IDX]);)
+
+	if (t->cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) {
+		/* reassign finger 1 and 2 positions to new tracks */
+		if (t->cur_tch > 0) {
+			/* reassign st finger1 */
+			if (use_trk_id) {
+				id = CY_MT_TCH1_IDX;
+				t->cur_st_tch[CY_ST_FNGR1_IDX] =
+							t->cur_mt_tch[id];
+			} else {
+				id = GET_TOUCH1_ID(xy->touch12_id);
+				t->cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			}
+			t->st_x1 = t->cur_mt_pos[id][CY_XPOS];
+			t->st_y1 = t->cur_mt_pos[id][CY_YPOS];
+			t->st_z1 = t->cur_mt_z[id];
+
+			DBG(printk(KERN_INFO"%s: ST STEP 1 - ST1 ID=%3d\n",
+				__func__, t->cur_st_tch[CY_ST_FNGR1_IDX]);)
+
+			if ((t->cur_tch > 1) &&
+				(t->cur_st_tch[CY_ST_FNGR2_IDX] >
+				CY_NUM_TRK_ID)) {
+				/* reassign st finger2 */
+				if (use_trk_id) {
+					id = CY_MT_TCH2_IDX;
+					t->cur_st_tch[CY_ST_FNGR2_IDX] =
+						t->cur_mt_tch[id];
+				} else {
+					id = GET_TOUCH2_ID(xy->touch12_id);
+					t->cur_st_tch[CY_ST_FNGR2_IDX] = id;
+				}
+				t->st_x2 = t->cur_mt_pos[id][CY_XPOS];
+				t->st_y2 = t->cur_mt_pos[id][CY_YPOS];
+				t->st_z2 = t->cur_mt_z[id];
+
+				DBG(
+				printk(KERN_INFO"%s: ST STEP 2 - ST2 ID=%3d\n",
+				__func__, t->cur_st_tch[CY_ST_FNGR2_IDX]);)
+			}
+		}
+	} else if (t->cur_st_tch[CY_ST_FNGR2_IDX] > CY_NUM_TRK_ID) {
+		if (t->cur_tch > 1) {
+			/* reassign st finger2 */
+			if (use_trk_id) {
+				/* reassign st finger2 */
+				id = CY_MT_TCH2_IDX;
+				t->cur_st_tch[CY_ST_FNGR2_IDX] =
+							t->cur_mt_tch[id];
+			} else {
+				/* reassign st finger2 */
+				id = GET_TOUCH2_ID(xy->touch12_id);
+				t->cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+			t->st_x2 = t->cur_mt_pos[id][CY_XPOS];
+			t->st_y2 = t->cur_mt_pos[id][CY_YPOS];
+			t->st_z2 = t->cur_mt_z[id];
+
+			DBG(printk(KERN_INFO"%s: ST STEP 3 - ST2 ID=%3d\n",
+				   __func__, t->cur_st_tch[CY_ST_FNGR2_IDX]);)
+		}
+	}
+	/* if the 1st touch is missing and there is a 2nd touch,
+	 * then set the 1st touch to 2nd touch and terminate 2nd touch
+	 */
+	if ((t->cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) &&
+			(t->cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID)) {
+		t->st_x1 = t->st_x2;
+		t->st_y1 = t->st_y2;
+		t->st_z1 = t->st_z2;
+		t->cur_st_tch[CY_ST_FNGR1_IDX] = t->cur_st_tch[CY_ST_FNGR2_IDX];
+		t->cur_st_tch[CY_ST_FNGR2_IDX] = CY_IGNR_TCH;
+	}
+	/* if the 2nd touch ends up equal to the 1st touch,
+	 * then just report a single touch */
+	if (t->cur_st_tch[CY_ST_FNGR1_IDX] == t->cur_st_tch[CY_ST_FNGR2_IDX])
+		t->cur_st_tch[CY_ST_FNGR2_IDX] = CY_IGNR_TCH;
+
+	/* set Single Touch current event signals */
+	if (t->cur_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) {
+		input_report_abs(ts->input, ABS_X, t->st_x1);
+		input_report_abs(ts->input, ABS_Y, t->st_y1);
+		input_report_abs(ts->input, ABS_PRESSURE, t->st_z1);
+		input_report_key(ts->input, BTN_TOUCH, CY_TCH);
+		input_report_abs(ts->input, ABS_TOOL_WIDTH, t->tool_width);
+
+		DBG(printk(KERN_INFO"%s:ST->F1:%3d X:%3d Y:%3d Z:%3d\n",
+			   __func__, t->cur_st_tch[CY_ST_FNGR1_IDX],
+			   t->st_x1, t->st_y1, t->st_z1);)
+
+		if (t->cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID) {
+			input_report_key(ts->input, BTN_2, CY_TCH);
+			input_report_abs(ts->input, ABS_HAT0X, t->st_x2);
+			input_report_abs(ts->input, ABS_HAT0Y, t->st_y2);
+
+			DBG(printk(KERN_INFO"%s:ST->F2:%3d X:%3d Y:%3d Z:%3d\n",
+				__func__, t->cur_st_tch[CY_ST_FNGR2_IDX],
+				t->st_x2, t->st_y2, t->st_z2);)
+		} else {
+			input_report_key(ts->input, BTN_2, CY_NTCH);
+		}
+	} else {
+		input_report_abs(ts->input, ABS_PRESSURE, CY_NTCH);
+		input_report_key(ts->input, BTN_TOUCH, CY_NTCH);
+		input_report_key(ts->input, BTN_2, CY_NTCH);
+	}
+	/* update platform data for the current single touch info */
+	ts->prv_st_tch[CY_ST_FNGR1_IDX] = t->cur_st_tch[CY_ST_FNGR1_IDX];
+	ts->prv_st_tch[CY_ST_FNGR2_IDX] = t->cur_st_tch[CY_ST_FNGR2_IDX];
+
+}
+
+void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
+{
+
+	u8 id;
+	u8 i, loc;
+	void (*mt_sync_func)(struct input_dev *) = ts->platform_data->mt_sync;
+
+	if (!ts->platform_data->use_trk_id)
+		goto no_track_id;
+
+	/* terminate any previous touch where the track
+	 * is missing from the current event */
+	for (id = 0; id < CY_NUM_TRK_ID; id++) {
+		if ((ts->act_trk[id] == CY_NTCH) || (t->cur_trk[id] != CY_NTCH))
+			continue;
+
+		input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
+		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, CY_NTCH);
+		input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, t->tool_width);
+		input_report_abs(ts->input, ABS_MT_POSITION_X,
+					ts->prv_mt_pos[id][CY_XPOS]);
+		input_report_abs(ts->input, ABS_MT_POSITION_Y,
+					ts->prv_mt_pos[id][CY_YPOS]);
+		if (mt_sync_func)
+			mt_sync_func(ts->input);
+		ts->act_trk[id] = CY_NTCH;
+		ts->prv_mt_pos[id][CY_XPOS] = 0;
+		ts->prv_mt_pos[id][CY_YPOS] = 0;
+	}
+	/* set Multi-Touch current event signals */
+	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+		if (t->cur_mt_tch[id] >= CY_NUM_TRK_ID)
+			continue;
+
+		input_report_abs(ts->input, ABS_MT_TRACKING_ID,
+						t->cur_mt_tch[id]);
+		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+						t->cur_mt_z[id]);
+		input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR,
+						t->tool_width);
+		input_report_abs(ts->input, ABS_MT_POSITION_X,
+						t->cur_mt_pos[id][CY_XPOS]);
+		input_report_abs(ts->input, ABS_MT_POSITION_Y,
+						t->cur_mt_pos[id][CY_YPOS]);
+		if (mt_sync_func)
+			mt_sync_func(ts->input);
+
+		ts->act_trk[id] = CY_TCH;
+		ts->prv_mt_pos[id][CY_XPOS] = t->cur_mt_pos[id][CY_XPOS];
+		ts->prv_mt_pos[id][CY_YPOS] = t->cur_mt_pos[id][CY_YPOS];
+	}
+	return;
+no_track_id:
+
+	/* set temporary track array elements to voids */
+	memset(t->tmp_trk, CY_IGNR_TCH, sizeof(t->tmp_trk));
+	memset(t->snd_trk, CY_IGNR_TCH, sizeof(t->snd_trk));
+
+	/* get what is currently active */
+	for (i = id = 0; id < CY_NUM_TRK_ID && i < CY_NUM_MT_TCH_ID; id++) {
+		if (t->cur_trk[id] == CY_TCH) {
+			/* only incr counter if track found */
+			t->tmp_trk[i] = id;
+			i++;
+		}
+	}
+	DBG(printk(KERN_INFO"%s: T1: t0=%d, t1=%d, t2=%d, t3=%d\n", __func__,
+					t->tmp_trk[0], t->tmp_trk[1],
+					t->tmp_trk[2], t->tmp_trk[3]);)
+	DBG(printk(KERN_INFO"%s: T1: p0=%d, p1=%d, p2=%d, p3=%d\n", __func__,
+					ts->prv_mt_tch[0], ts->prv_mt_tch[1],
+					ts->prv_mt_tch[2], ts->prv_mt_tch[3]);)
+
+	/* pack in still active previous touches */
+	for (id = t->prv_tch = 0; id < CY_NUM_MT_TCH_ID; id++) {
+		if (t->tmp_trk[id] >= CY_NUM_TRK_ID)
+			continue;
+
+		if (cyttsp_inlist(ts->prv_mt_tch, t->tmp_trk[id], &loc,
+							CY_NUM_MT_TCH_ID)) {
+			loc &= CY_NUM_MT_TCH_ID - 1;
+			t->snd_trk[loc] = t->tmp_trk[id];
+			t->prv_tch++;
+			DBG(printk(KERN_INFO"%s: in list s[%d]=%d "
+					"t[%d]=%d, loc=%d p=%d\n", __func__,
+					loc, t->snd_trk[loc],
+					id, t->tmp_trk[id],
+					loc, t->prv_tch);)
+		} else {
+			DBG(printk(KERN_INFO"%s: is not in list s[%d]=%d"
+					" t[%d]=%d loc=%d\n", __func__,
+					id, t->snd_trk[id],
+					id, t->tmp_trk[id],
+					loc);)
+		}
+	}
+	DBG(printk(KERN_INFO"%s: S1: s0=%d, s1=%d, s2=%d, s3=%d p=%d\n",
+		   __func__,
+		   t->snd_trk[0], t->snd_trk[1], t->snd_trk[2],
+		   t->snd_trk[3], t->prv_tch);)
+
+	/* pack in new touches */
+	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+		if (t->tmp_trk[id] >= CY_NUM_TRK_ID)
+			continue;
+
+		if (!cyttsp_inlist(t->snd_trk, t->tmp_trk[id], &loc,
+							CY_NUM_MT_TCH_ID)) {
+
+			DBG(
+			printk(KERN_INFO"%s: not in list t[%d]=%d, loc=%d\n",
+				   __func__,
+				   id, t->tmp_trk[id], loc);)
+
+			if (cyttsp_next_avail_inlist(t->snd_trk, &loc,
+							CY_NUM_MT_TCH_ID)) {
+				loc &= CY_NUM_MT_TCH_ID - 1;
+				t->snd_trk[loc] = t->tmp_trk[id];
+				DBG(printk(KERN_INFO "%s: put in list s[%d]=%d"
+					" t[%d]=%d\n", __func__,
+					loc,
+					t->snd_trk[loc], id, t->tmp_trk[id]);
+				    )
+			}
+		} else {
+			DBG(printk(KERN_INFO"%s: is in list s[%d]=%d "
+				"t[%d]=%d loc=%d\n", __func__,
+				id, t->snd_trk[id], id, t->tmp_trk[id], loc);)
+		}
+	}
+	DBG(printk(KERN_INFO"%s: S2: s0=%d, s1=%d, s2=%d, s3=%d\n", __func__,
+			t->snd_trk[0], t->snd_trk[1],
+			t->snd_trk[2], t->snd_trk[3]);)
+
+	/* sync motion event signals for each current touch */
+	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+		/* z will either be 0 (NOTOUCH) or
+		 * some pressure (TOUCH)
+		 */
+		DBG(printk(KERN_INFO "%s: MT0 prev[%d]=%d "
+				"temp[%d]=%d send[%d]=%d\n",
+				__func__, id, ts->prv_mt_tch[id],
+				id, t->tmp_trk[id], id, t->snd_trk[id]);)
+
+		if (t->snd_trk[id] < CY_NUM_TRK_ID) {
+			input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+					t->cur_mt_z[t->snd_trk[id]]);
+			input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR,
+					t->tool_width);
+			input_report_abs(ts->input, ABS_MT_POSITION_X,
+					t->cur_mt_pos[t->snd_trk[id]][CY_XPOS]);
+			input_report_abs(ts->input, ABS_MT_POSITION_Y,
+					t->cur_mt_pos[t->snd_trk[id]][CY_YPOS]);
+			if (mt_sync_func)
+				mt_sync_func(ts->input);
+
+			DBG(printk(KERN_INFO"%s: MT1 -> TID:"
+				"%3d X:%3d  Y:%3d  Z:%3d\n", __func__,
+				t->snd_trk[id],
+				t->cur_mt_pos[t->snd_trk[id]][CY_XPOS],
+				t->cur_mt_pos[t->snd_trk[id]][CY_YPOS],
+				t->cur_mt_z[t->snd_trk[id]]);)
+
+		} else if (ts->prv_mt_tch[id] < CY_NUM_TRK_ID) {
+			/* void out this touch */
+			input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR,
+							CY_NTCH);
+			input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR,
+							t->tool_width);
+			input_report_abs(ts->input, ABS_MT_POSITION_X,
+				ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS]);
+			input_report_abs(ts->input, ABS_MT_POSITION_Y,
+				ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS]);
+
+			if (mt_sync_func)
+				mt_sync_func(ts->input);
+
+			DBG(printk(KERN_INFO"%s: "
+				"MT2->TID:%2d X:%3d Y:%3d Z:%3d liftoff-sent\n",
+				__func__, ts->prv_mt_tch[id],
+				ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS],
+				ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS],
+				CY_NTCH);)
+		} else {
+			/* do not stuff any signals for this
+			 * previously and currently void touches
+			 */
+			DBG(printk(KERN_INFO"%s: "
+				"MT3->send[%d]=%d - No touch - NOT sent\n",
+				__func__, id, t->snd_trk[id]);)
+		}
+	}
+
+	/* save current posted tracks to
+	 * previous track memory */
+	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+		ts->prv_mt_tch[id] = t->snd_trk[id];
+		if (t->snd_trk[id] < CY_NUM_TRK_ID) {
+			ts->prv_mt_pos[t->snd_trk[id]][CY_XPOS] =
+					t->cur_mt_pos[t->snd_trk[id]][CY_XPOS];
+			ts->prv_mt_pos[t->snd_trk[id]][CY_YPOS] =
+					t->cur_mt_pos[t->snd_trk[id]][CY_YPOS];
+			DBG(printk(KERN_INFO"%s: "
+				"MT4->TID:%2d X:%3d Y:%3d Z:%3d save for prv\n",
+				__func__, t->snd_trk[id],
+				ts->prv_mt_pos[t->snd_trk[id]][CY_XPOS],
+				ts->prv_mt_pos[t->snd_trk[id]][CY_YPOS],
+				CY_NTCH);)
+		}
+	}
+	memset(ts->act_trk, CY_NTCH, sizeof(ts->act_trk));
+	for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
+		if (t->snd_trk[id] < CY_NUM_TRK_ID)
+			ts->act_trk[t->snd_trk[id]] = CY_TCH;
+	}
+}
+
+void cyttsp_xy_worker(struct cyttsp *ts)
+{
+	struct cyttsp_xydata xy_data;
+	u8 id, tilt, rev_x, rev_y;
+	struct cyttsp_track_data trc;
+	s32 retval;
+
+	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
+	/* get event data from CYTTSP device */
+	retval = ttsp_read_block_data(ts, CY_REG_BASE,
+				      sizeof(xy_data), &xy_data);
+
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Error, fail to read device on i2c bus\n",
+			__func__);
+		goto exit_xy_worker;
+	}
+
+	/* touch extension handling */
+	retval = ttsp_tch_ext(ts, &xy_data);
+
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Error, touch extension handling\n",
+			__func__);
+		goto exit_xy_worker;
+	} else if (retval > 0) {
+		DBG(printk(KERN_INFO "%s: Touch extension handled\n",
+			__func__);)
+		goto exit_xy_worker;
+	}
+
+	/* provide flow control handshake */
+	if (ts->irq) {
+		if (ts->platform_data->use_hndshk) {
+			u8 cmd;
+			cmd = xy_data.hst_mode & CY_HNDSHK_BIT ?
+				xy_data.hst_mode & ~CY_HNDSHK_BIT :
+				xy_data.hst_mode | CY_HNDSHK_BIT;
+			retval = ttsp_write_block_data(ts, CY_REG_BASE,
+						       sizeof(cmd), (u8 *)&cmd);
+		}
+	}
+	trc.cur_tch = GET_NUM_TOUCHES(xy_data.tt_stat);
+	if (GET_HSTMODE(xy_data.hst_mode) != CY_OPERATE_MODE) {
+		/* terminate all active tracks */
+		trc.cur_tch = CY_NTCH;
+		DBG(printk(KERN_INFO "%s: Invalid mode detected\n",
+			__func__);)
+	} else if (IS_LARGE_AREA(xy_data.tt_stat) == 1) {
+		/* terminate all active tracks */
+		trc.cur_tch = CY_NTCH;
+		DBG(printk(KERN_INFO "%s: Large area detected\n",
+			__func__);)
+	} else if (trc.cur_tch > CY_NUM_MT_TCH_ID) {
+		/* terminate all active tracks */
+		trc.cur_tch = CY_NTCH;
+		DBG(printk(KERN_INFO "%s: Num touch error detected\n",
+			__func__);)
+	} else if (IS_BAD_PKT(xy_data.tt_mode)) {
+		/* terminate all active tracks */
+		trc.cur_tch = CY_NTCH;
+		DBG(printk(KERN_INFO "%s: Invalid buffer detected\n",
+			__func__);)
+	}
+
+	/* set tool size */
+	trc.tool_width = CY_SMALL_TOOL_WIDTH;
+
+	if (ts->platform_data->gen == CY_GEN2) {
+		/* translate Gen2 interface data into comparable Gen3 data */
+		trc.cur_tch = ttsp_convert_gen2(trc.cur_tch, &xy_data);
+	}
+
+	/* clear current active track ID array and count previous touches */
+	for (id = 0, trc.prv_tch = CY_NTCH; id < CY_NUM_TRK_ID; id++) {
+		trc.cur_trk[id] = CY_NTCH;
+		trc.prv_tch += ts->act_trk[id];
+	}
+
+	/* send no events if there were no previous touches */
+	/* and no new touches */
+	if ((trc.prv_tch == CY_NTCH) && ((trc.cur_tch == CY_NTCH) ||
+				(trc.cur_tch > CY_NUM_MT_TCH_ID)))
+		goto exit_xy_worker;
+
+	DBG(printk(KERN_INFO "%s: prev=%d  curr=%d\n", __func__,
+		   trc.prv_tch, trc.cur_tch);)
+
+	/* clear current single-touch array */
+	memset(trc.cur_st_tch, CY_IGNR_TCH, sizeof(trc.cur_st_tch));
+
+	/* clear single touch positions */
+	trc.st_x1 = trc.st_y1 = trc.st_z1 =
+			trc.st_x2 = trc.st_y2 = trc.st_z2 = CY_NTCH;
+
+	/* clear current multi-touch arrays */
+	memset(trc.cur_mt_tch, CY_IGNR_TCH, sizeof(trc.cur_mt_tch));
+	memset(trc.cur_mt_pos, CY_NTCH, sizeof(trc.cur_mt_pos));
+	memset(trc.cur_mt_z, CY_NTCH, sizeof(trc.cur_mt_z));
+
+	DBG(
+	if (trc.cur_tch) {
+		unsigned i;
+		u8 *pdata = (u8 *)&xy_data;
+
+		printk(KERN_INFO "%s: TTSP data_pack: ", __func__);
+		for (i = 0; i < sizeof(struct cyttsp_xydata); i++)
+			printk(KERN_INFO "[%d]=0x%x ", i, pdata[i]);
+		printk(KERN_INFO "\n");
+	})
+
+	/* Determine if display is tilted */
+	tilt = !!FLIP_DATA(ts->platform_data->flags);
+	/* Check for switch in origin */
+	rev_x = !!REVERSE_X(ts->platform_data->flags);
+	rev_y = !!REVERSE_Y(ts->platform_data->flags);
+
+	/* process the touches */
+	switch (trc.cur_tch) {
+	case 4:
+		xy_data.x4 = be16_to_cpu(xy_data.x4);
+		xy_data.y4 = be16_to_cpu(xy_data.y4);
+		if (tilt)
+			FLIP_XY(xy_data.x4, xy_data.y4);
+
+		if (rev_x)
+			xy_data.x4 = INVERT_X(xy_data.x4,
+					ts->platform_data->maxx);
+		if (rev_y)
+			xy_data.y4 = INVERT_X(xy_data.y4,
+					ts->platform_data->maxy);
+
+		id = GET_TOUCH4_ID(xy_data.touch34_id);
+		if (ts->platform_data->use_trk_id) {
+			trc.cur_mt_pos[CY_MT_TCH4_IDX][CY_XPOS] = xy_data.x4;
+			trc.cur_mt_pos[CY_MT_TCH4_IDX][CY_YPOS] = xy_data.y4;
+			trc.cur_mt_z[CY_MT_TCH4_IDX] = xy_data.z4;
+		} else {
+			trc.cur_mt_pos[id][CY_XPOS] = xy_data.x4;
+			trc.cur_mt_pos[id][CY_YPOS] = xy_data.y4;
+			trc.cur_mt_z[id] = xy_data.z4;
+		}
+		trc.cur_mt_tch[CY_MT_TCH4_IDX] = id;
+		trc.cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <	CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				trc.st_x1 = xy_data.x4;
+				trc.st_y1 = xy_data.y4;
+				trc.st_z1 = xy_data.z4;
+				trc.cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				trc.st_x2 = xy_data.x4;
+				trc.st_y2 = xy_data.y4;
+				trc.st_z2 = xy_data.z4;
+				trc.cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		DBG(printk(KERN_INFO"%s: 4th XYZ:% 3d,% 3d,% 3d  ID:% 2d\n\n",
+				__func__, xy_data.x4, xy_data.y4, xy_data.z4,
+				(xy_data.touch34_id & 0x0F));)
+
+		/* do not break */
+	case 3:
+		xy_data.x3 = be16_to_cpu(xy_data.x3);
+		xy_data.y3 = be16_to_cpu(xy_data.y3);
+		if (tilt)
+			FLIP_XY(xy_data.x3, xy_data.y3);
+
+		if (rev_x)
+			xy_data.x3 = INVERT_X(xy_data.x3,
+					ts->platform_data->maxx);
+		if (rev_y)
+			xy_data.y3 = INVERT_X(xy_data.y3,
+					ts->platform_data->maxy);
+
+		id = GET_TOUCH3_ID(xy_data.touch34_id);
+		if (ts->platform_data->use_trk_id) {
+			trc.cur_mt_pos[CY_MT_TCH3_IDX][CY_XPOS] = xy_data.x3;
+			trc.cur_mt_pos[CY_MT_TCH3_IDX][CY_YPOS] = xy_data.y3;
+			trc.cur_mt_z[CY_MT_TCH3_IDX] = xy_data.z3;
+		} else {
+			trc.cur_mt_pos[id][CY_XPOS] = xy_data.x3;
+			trc.cur_mt_pos[id][CY_YPOS] = xy_data.y3;
+			trc.cur_mt_z[id] = xy_data.z3;
+		}
+		trc.cur_mt_tch[CY_MT_TCH3_IDX] = id;
+		trc.cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				trc.st_x1 = xy_data.x3;
+				trc.st_y1 = xy_data.y3;
+				trc.st_z1 = xy_data.z3;
+				trc.cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				trc.st_x2 = xy_data.x3;
+				trc.st_y2 = xy_data.y3;
+				trc.st_z2 = xy_data.z3;
+				trc.cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		DBG(printk(KERN_INFO"%s: 3rd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n",
+			__func__, xy_data.x3, xy_data.y3, xy_data.z3,
+			((xy_data.touch34_id >> 4) & 0x0F));)
+
+		/* do not break */
+	case 2:
+		xy_data.x2 = be16_to_cpu(xy_data.x2);
+		xy_data.y2 = be16_to_cpu(xy_data.y2);
+		if (tilt)
+			FLIP_XY(xy_data.x2, xy_data.y2);
+
+		if (rev_x)
+			xy_data.x2 = INVERT_X(xy_data.x2,
+					ts->platform_data->maxx);
+		if (rev_y)
+			xy_data.y2 = INVERT_X(xy_data.y2,
+					ts->platform_data->maxy);
+		id = GET_TOUCH2_ID(xy_data.touch12_id);
+		if (ts->platform_data->use_trk_id) {
+			trc.cur_mt_pos[CY_MT_TCH2_IDX][CY_XPOS] = xy_data.x2;
+			trc.cur_mt_pos[CY_MT_TCH2_IDX][CY_YPOS] = xy_data.y2;
+			trc.cur_mt_z[CY_MT_TCH2_IDX] = xy_data.z2;
+		} else {
+			trc.cur_mt_pos[id][CY_XPOS] = xy_data.x2;
+			trc.cur_mt_pos[id][CY_YPOS] = xy_data.y2;
+			trc.cur_mt_z[id] = xy_data.z2;
+		}
+		trc.cur_mt_tch[CY_MT_TCH2_IDX] = id;
+		trc.cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <	CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				trc.st_x1 = xy_data.x2;
+				trc.st_y1 = xy_data.y2;
+				trc.st_z1 = xy_data.z2;
+				trc.cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				trc.st_x2 = xy_data.x2;
+				trc.st_y2 = xy_data.y2;
+				trc.st_z2 = xy_data.z2;
+				trc.cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		DBG(printk(KERN_INFO"%s: 2nd XYZ:% 3d,% 3d,% 3d  ID:% 2d\n",
+				__func__, xy_data.x2, xy_data.y2, xy_data.z2,
+				(xy_data.touch12_id & 0x0F));)
+
+		/* do not break */
+	case 1:
+		xy_data.x1 = be16_to_cpu(xy_data.x1);
+		xy_data.y1 = be16_to_cpu(xy_data.y1);
+		if (tilt)
+			FLIP_XY(xy_data.x1, xy_data.y1);
+
+		if (rev_x)
+			xy_data.x1 = INVERT_X(xy_data.x1,
+					ts->platform_data->maxx);
+		if (rev_y)
+			xy_data.y1 = INVERT_X(xy_data.y1,
+					ts->platform_data->maxy);
+
+		id = GET_TOUCH1_ID(xy_data.touch12_id);
+		if (ts->platform_data->use_trk_id) {
+			trc.cur_mt_pos[CY_MT_TCH1_IDX][CY_XPOS] = xy_data.x1;
+			trc.cur_mt_pos[CY_MT_TCH1_IDX][CY_YPOS] = xy_data.y1;
+			trc.cur_mt_z[CY_MT_TCH1_IDX] = xy_data.z1;
+		} else {
+			trc.cur_mt_pos[id][CY_XPOS] = xy_data.x1;
+			trc.cur_mt_pos[id][CY_YPOS] = xy_data.y1;
+			trc.cur_mt_z[id] = xy_data.z1;
+		}
+		trc.cur_mt_tch[CY_MT_TCH1_IDX] = id;
+		trc.cur_trk[id] = CY_TCH;
+		if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <	CY_NUM_TRK_ID) {
+			if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
+				trc.st_x1 = xy_data.x1;
+				trc.st_y1 = xy_data.y1;
+				trc.st_z1 = xy_data.z1;
+				trc.cur_st_tch[CY_ST_FNGR1_IDX] = id;
+			} else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
+				trc.st_x2 = xy_data.x1;
+				trc.st_y2 = xy_data.y1;
+				trc.st_z2 = xy_data.z1;
+				trc.cur_st_tch[CY_ST_FNGR2_IDX] = id;
+			}
+		}
+		DBG(printk(KERN_INFO"%s: S1st XYZ:% 3d,% 3d,% 3d  ID:% 2d\n",
+				__func__, xy_data.x1, xy_data.y1, xy_data.z1,
+				((xy_data.touch12_id >> 4) & 0x0F));)
+
+		break;
+	case 0:
+	default:
+		break;
+	}
+
+	if (ts->platform_data->use_st)
+		handle_single_touch(&xy_data, &trc, ts);
+
+	if (ts->platform_data->use_mt)
+		handle_multi_touch(&trc, ts);
+
+	/* handle gestures */
+	if (ts->platform_data->use_gestures && xy_data.gest_id) {
+		input_report_key(ts->input, BTN_3, CY_TCH);
+		input_report_abs(ts->input, ABS_HAT1X, xy_data.gest_id);
+		input_report_abs(ts->input, ABS_HAT2Y, xy_data.gest_cnt);
+	}
+
+	/* signal the view motion event */
+	input_sync(ts->input);
+
+	/* update platform data for the current multi-touch information */
+	memcpy(ts->act_trk, trc.cur_trk, CY_NUM_TRK_ID);
+
+exit_xy_worker:
+	DBG(printk(KERN_INFO"%s: finished.\n", __func__);)
+	return;
+}
+
+/* ************************************************************************
+ * ISR function. This function is general, initialized in drivers init
+ * function and disables further IRQs until this IRQ is processed in worker.
+ * *************************************************************************/
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = (struct cyttsp *)handle;
+
+	DBG(printk(KERN_INFO"%s: Got IRQ!\n", __func__);)
+	cyttsp_xy_worker(ts);
+	return IRQ_HANDLED;
+}
+
+/* schedulable worker entry for timer polling method */
+void cyttsp_xy_worker_(struct work_struct *work)
+{
+	struct cyttsp *ts = container_of(work, struct cyttsp, work);
+	cyttsp_xy_worker(ts);
+}
+
+/* Timer function used as touch interrupt generator for polling method */
+static void cyttsp_timer(unsigned long handle)
+{
+	struct cyttsp *ts = (struct cyttsp *)handle;
+
+	DBG(printk(KERN_INFO"%s: TTSP timer event!\n", __func__);)
+	/* schedule motion signal handling */
+	if (!work_pending(&ts->work))
+		schedule_work(&ts->work);
+	mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
+	return;
+}
+
+
+/* ************************************************************************
+ * Probe initialization functions
+ * ************************************************************************ */
+static int cyttsp_load_bl_regs(struct cyttsp *ts)
+{
+	int retval;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
+				sizeof(ts->bl_data), &(ts->bl_data));
+
+	if (retval < 0) {
+		DBG(printk(KERN_INFO "%s: Failed reading block data, err:%d\n",
+			__func__, retval);)
+		goto fail;
+	}
+
+	DBG({
+	      int i;
+	      u8 *bl_data = (u8 *)&(ts->bl_data);
+	      for (i = 0; i < sizeof(struct cyttsp_bootloader_data); i++)
+			printk(KERN_INFO "%s bl_data[%d]=0x%x\n",
+				__func__, i, bl_data[i]);
+	})
+
+	return 0;
+fail:
+	return retval;
+}
+
+static int cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries = 0;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(bl_cmd),
+				       (void *)bl_cmd);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Failed writing block data, err:%d\n",
+			__func__, retval);
+		goto fail;
+	}
+	do {
+		msleep(500);
+		cyttsp_load_bl_regs(ts);
+	} while (GET_BOOTLOADERMODE(ts->bl_data.bl_status) && tries++ < 10);
+	return 0;
+fail:
+	return retval;
+}
+
+static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+	int retval;
+	u8 cmd = CY_SYSINFO_MODE;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	/* wait for TTSP Device to complete switch to SysInfo mode */
+	msleep(500);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Failed writing block data, err:%d\n",
+			__func__, retval);
+		goto write_block_data_fail;
+	}
+	retval = ttsp_read_block_data(ts, CY_REG_BASE, sizeof(ts->sysinfo_data),
+			&(ts->sysinfo_data));
+
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Failed reading block data, err:%d\n",
+			__func__, retval);
+		goto read_block_data_fail;
+	}
+
+	DBG(printk(KERN_INFO"%s:SI2: hst_mode=0x%02X mfg_cmd=0x%02X "
+		"mfg_stat=0x%02X\n", __func__, ts->sysinfo_data.hst_mode,
+		ts->sysinfo_data.mfg_cmd,
+		ts->sysinfo_data.mfg_stat);)
+
+	DBG(printk(KERN_INFO"%s:SI2: bl_ver=0x%02X%02X\n",
+		__func__, ts->sysinfo_data.bl_verh, ts->sysinfo_data.bl_verl);)
+
+	DBG(printk(KERN_INFO"%s:SI2: sysinfo act_intrvl=0x%02X "
+		"tch_tmout=0x%02X lp_intrvl=0x%02X\n",
+		__func__, ts->sysinfo_data.act_intrvl,
+		ts->sysinfo_data.tch_tmout,
+		ts->sysinfo_data.lp_intrvl);)
+
+	printk(KERN_INFO"%s:SI2:tts_ver=0x%02X%02X app_id=0x%02X%02X "
+		"app_ver=0x%02X%02X c_id=0x%02X%02X%02X\n", __func__,
+		ts->sysinfo_data.tts_verh, ts->sysinfo_data.tts_verl,
+		ts->sysinfo_data.app_idh, ts->sysinfo_data.app_idl,
+		ts->sysinfo_data.app_verh, ts->sysinfo_data.app_verl,
+		ts->sysinfo_data.cid[0], ts->sysinfo_data.cid[1],
+		ts->sysinfo_data.cid[2]);
+	return 0;
+
+write_block_data_fail:
+read_block_data_fail:
+	return retval;
+}
+
+static int cyttsp_set_operational_mode(struct cyttsp *ts)
+{
+	int retval;
+	u8 cmd = CY_OPERATE_MODE;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Failed writing block data, err:%d\n",
+			__func__, retval);
+		goto write_block_data_fail;
+	}
+	/* wait for TTSP Device to complete switch to Operational mode */
+	msleep(500);
+	return 0;
+write_block_data_fail:
+	return retval;
+}
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+	int retval;
+	int tries;
+	u8 cmd = CY_SOFT_RESET_MODE;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+	/* reset TTSP Device back to bootloader mode */
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	/* wait for TTSP Device to complete reset back to bootloader */
+	tries = 0;
+	msleep(200);
+	do {
+		msleep(100);
+		cyttsp_load_bl_regs(ts);
+	} while (ts->bl_data.bl_status != 0x10 &&
+		ts->bl_data.bl_status != 0x11 &&
+		tries++ < 100);
+	if (tries >= 100)
+		printk(KERN_ERR "%s: bootlodader not ready, status 0x%02x\n",
+			__func__, ts->bl_data.bl_status);
+	return retval;
+}
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+	int retval = 0;
+	u8 cmd;
+	int tries = 0;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+	/* check if the TTSP device has a bootloader installed */
+	retval = cyttsp_soft_reset(ts);
+	if (retval < 0)
+		goto bypass;
+
+	do {
+		msleep(500);
+		retval = cyttsp_load_bl_regs(ts);
+	} while (!GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
+		!(GET_HSTMODE(ts->bl_data.bl_file) == CY_OPERATE_MODE) &&
+		tries++ < 10);
+
+	/* is bootloader missing? */
+	if (!GET_BOOTLOADERMODE(ts->bl_data.bl_status)) {
+		/* skip all bootloader and sys info and */
+		/* go straight to operational mode */
+		if (!(retval < 0)) {
+			cyttsp_set_operational_mode(ts);
+			goto bypass;
+		}
+	}
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_exit_bl_mode(ts);
+
+	if (retval < 0)
+		goto bypass;
+
+	/* switch to System Information mode to read */
+	/* versions and set interval registers */
+	retval = cyttsp_set_sysinfo_mode(ts);
+	if (retval < 0)
+		goto bypass;
+	if ((CY_DIFF(ts->platform_data->act_intrvl, CY_ACT_INTRVL_DFLT) ||
+		CY_DIFF(ts->platform_data->tch_tmout, CY_TCH_TMOUT_DFLT) ||
+		CY_DIFF(ts->platform_data->lp_intrvl, CY_LP_INTRVL_DFLT))) {
+
+		u8 intrvl_ray[3];
+
+		intrvl_ray[0] = ts->platform_data->act_intrvl;
+		intrvl_ray[1] = ts->platform_data->tch_tmout;
+		intrvl_ray[2] = ts->platform_data->lp_intrvl;
+
+		DBG(printk(KERN_INFO"%s: act_intrvl=0x%02X"
+			"tch_tmout=0x%02X lp_intrvl=0x%02X\n",
+			__func__, ts->platform_data->act_intrvl,
+			ts->platform_data->tch_tmout,
+			ts->platform_data->lp_intrvl);)
+
+		/* set intrvl registers */
+		retval = ttsp_write_block_data(ts,
+				CY_REG_ACT_INTRVL,
+					sizeof(intrvl_ray), intrvl_ray);
+
+		msleep(CY_DELAY_SYSINFO);
+	}
+	/* switch back to Operational mode */
+	DBG(printk(KERN_INFO"%s: switch back to operational mode\n",
+		__func__);)
+	if (retval < 0)
+		goto bypass;
+
+	cmd = CY_OPERATE_MODE;
+	retval = ttsp_write_block_data(ts,
+		CY_REG_BASE, sizeof(cmd), &cmd);
+	/* wait for TTSP Device to complete switch to */
+	/* Operational mode */
+	msleep(1000);
+	/* init gesture setup */
+	if (retval < 0)
+		goto bypass;
+
+	if (ts->platform_data->use_gestures) {
+		u8 gesture_setup;
+
+		DBG(printk(KERN_INFO"%s: Init gesture setup\n", __func__);)
+
+		gesture_setup = ts->platform_data->gest_set;
+		retval = ttsp_write_block_data(ts, CY_REG_GEST_SET,
+				sizeof(gesture_setup), &gesture_setup);
+		msleep(CY_DELAY_DFLT);
+	}
+
+bypass:
+	if (retval < 0)
+		ts->platform_data->power_state = CY_IDLE_STATE;
+	else
+		ts->platform_data->power_state = CY_ACTIVE_STATE;
+
+	DBG(printk(KERN_INFO"%s: Power state is %s\n",
+			__func__, (ts->platform_data->power_state ==
+			CY_ACTIVE_STATE) ? "ACTIVE" : "IDLE");)
+	return retval;
+}
+
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle)
+{
+	int retval = 0;
+	struct cyttsp *ts = container_of(handle, struct cyttsp, pdev);
+	struct cyttsp_xydata xydata;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+	LOCK(ts->mutex);
+	if (!ts->fw_loader_mode && ts->suspended) {
+		ts->suspended = 0;
+		if (ts->platform_data->use_sleep &&
+			(ts->platform_data->power_state != CY_ACTIVE_STATE)) {
+			if (ts->platform_data->wakeup)
+				retval = ts->platform_data->wakeup();
+
+			if (retval < 0)
+				printk(KERN_ERR "%s:"
+					" Error, wakeup failed!\n",
+					__func__);
+			else {
+				if (ts->platform_data->use_timer)
+					mod_timer(&ts->timer,
+					jiffies + TOUCHSCREEN_TIMEOUT);
+				else
+					enable_irq(ts->irq);
+				retval = ttsp_read_block_data(ts, CY_REG_BASE,
+					sizeof(xydata), &xydata);
+				if (!(retval < 0) &&
+					(GET_HSTMODE(xydata.hst_mode) ==
+					CY_OPERATE_MODE))
+					ts->platform_data->power_state =
+						CY_ACTIVE_STATE;
+			}
+		}
+	}
+	UNLOCK(ts->mutex);
+	DBG(printk(KERN_INFO"%s: Wake Up %s\n", __func__,
+		(retval < 0) ? "FAIL" : "PASS");)
+	return retval;
+}
+
+int cyttsp_suspend(void *handle)
+{
+	struct cyttsp *ts = container_of(handle, struct cyttsp, pdev);
+	u8 sleep_mode = 0;
+	int retval = 0;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	LOCK(ts->mutex);
+	if (!ts->fw_loader_mode) {
+		if (ts->platform_data->use_timer) {
+			del_timer(&ts->timer);
+			cancel_work_sync(&ts->work);
+		} else {
+			/* this call waits for any pending IRQ handlers */
+			disable_irq(ts->irq);
+		}
+		ts->suspended = 1;
+		if (ts->platform_data->use_sleep &&
+				(ts->platform_data->power_state ==
+				CY_ACTIVE_STATE)) {
+			sleep_mode = CY_DEEP_SLEEP_MODE;
+			retval = ttsp_write_block_data(ts,
+				CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
+			if (!(retval < 0))
+				ts->platform_data->power_state = CY_SLEEP_STATE;
+		}
+		DBG(printk(KERN_INFO"%s: Sleep Power state is %s\n", __func__,
+			(ts->platform_data->power_state == CY_ACTIVE_STATE) ?
+			"ACTIVE" :
+			((ts->platform_data->power_state == CY_SLEEP_STATE) ?
+			"SLEEP" : "LOW POWER"));)
+	}
+	UNLOCK(ts->mutex);
+	return retval;
+}
+#endif
+
+static ssize_t firmware_write(struct kobject *kobj,
+				struct bin_attribute *bin_attr,
+				char *buf, loff_t pos, size_t size)
+{
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct cyttsp *ts = dev_get_drvdata(dev);
+	LOCK(ts->mutex);
+	DBG({
+		char str[128];
+		char *p = str;
+		int i;
+		for (i = 0; i < size; i++, p += 2)
+			sprintf(p, "%02x", (unsigned char)buf[i]);
+		printk(KERN_DEBUG "%s: size %d, pos %ld payload %s\n",
+		       __func__, size, (long)pos, str);
+	})
+	ttsp_write_block_data(ts, CY_REG_BASE, size, buf);
+	UNLOCK(ts->mutex);
+	return size;
+}
+
+static ssize_t firmware_read(struct kobject *kobj,
+	struct bin_attribute *ba,
+	char *buf, loff_t pos, size_t size)
+{
+	int count = 0;
+	struct device *dev = container_of(kobj, struct device, kobj);
+	struct cyttsp *ts = dev_get_drvdata(dev);
+
+	LOCK(ts->mutex);
+	if (!ts->fw_loader_mode)
+		goto exit;
+	if (!cyttsp_load_bl_regs(ts)) {
+		*(unsigned short *)buf = ts->bl_data.bl_status << 8 |
+			ts->bl_data.bl_error;
+		count = sizeof(unsigned short);
+	} else {
+		printk(KERN_ERR "%s: error reading status\n", __func__);
+		count = 0;
+	}
+exit:
+	UNLOCK(ts->mutex);
+	return count;
+}
+
+static struct bin_attribute cyttsp_firmware = {
+	.attr = {
+		.name = "firmware",
+		.mode = 0644,
+	},
+	.size = 128,
+	.read = firmware_read,
+	.write = firmware_write,
+};
+
+static ssize_t attr_fwloader_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct cyttsp *ts = dev_get_drvdata(dev);
+	return sprintf(buf, "0x%02X%02X 0x%02X%02X 0x%02X%02X 0x%02X%02X%02X\n",
+		ts->sysinfo_data.tts_verh, ts->sysinfo_data.tts_verl,
+		ts->sysinfo_data.app_idh, ts->sysinfo_data.app_idl,
+		ts->sysinfo_data.app_verh, ts->sysinfo_data.app_verl,
+		ts->sysinfo_data.cid[0], ts->sysinfo_data.cid[1],
+		ts->sysinfo_data.cid[2]);
+}
+
+static ssize_t attr_fwloader_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t size)
+{
+	char *p;
+	int ret;
+	struct cyttsp *ts = dev_get_drvdata(dev);
+	unsigned val = simple_strtoul(buf, &p, 10);
+
+	ret = p - buf;
+	if (*p && isspace(*p))
+		ret++;
+	printk(KERN_DEBUG "%s: %u\n", __func__, val);
+
+	LOCK(ts->mutex)
+	if (val && !ts->fw_loader_mode) {
+		ts->fw_loader_mode = 1;
+		if (ts->suspended) {
+			cyttsp_resume(ts);
+		} else {
+			if (ts->platform_data->use_timer)
+				del_timer(&ts->timer);
+			else
+				disable_irq_nosync(ts->irq);
+			cancel_work_sync(&ts->work);
+		}
+		ts->suspended = 0;
+		if (sysfs_create_bin_file(&dev->kobj, &cyttsp_firmware))
+			printk(KERN_ERR "%s: unable to create file\n",
+				__func__);
+		cyttsp_soft_reset(ts);
+		printk(KERN_INFO "%s: FW loader started.\n", __func__);
+	} else if (!val && ts->fw_loader_mode) {
+		sysfs_remove_bin_file(&dev->kobj, &cyttsp_firmware);
+		cyttsp_soft_reset(ts);
+		cyttsp_exit_bl_mode(ts);
+		cyttsp_set_sysinfo_mode(ts);
+		cyttsp_set_operational_mode(ts);
+
+		if (ts->platform_data->use_timer)
+			mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
+		else
+			enable_irq(ts->irq);
+		ts->fw_loader_mode = 0;
+		printk(KERN_INFO "%s: FW loader finished.\n", __func__);
+	}
+	UNLOCK(ts->mutex);
+	return  ret == size ? ret : -EINVAL;
+}
+
+static struct device_attribute fwloader =
+	__ATTR(fwloader, 0644, attr_fwloader_show, attr_fwloader_store);
+
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *pdev)
+{
+	struct input_dev *input_device;
+	struct cyttsp *ts;
+	int retval = 0;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (ts == NULL) {
+		printk(KERN_ERR "%s: Error, kzalloc\n", __func__);
+		goto error_alloc_data_failed;
+	}
+	mutex_init(&ts->mutex);
+	ts->pdev = pdev;
+	ts->platform_data = pdev->platform_data;
+	ts->bus_ops = bus_ops;
+
+	if (ts->platform_data->init)
+		retval = ts->platform_data->init(1);
+	if (retval) {
+		printk(KERN_ERR "%s: platform init failed!\n", __func__);
+		goto error_init;
+	}
+
+	if (ts->platform_data->use_timer)
+		ts->irq = -1;
+	else
+		ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
+
+	retval = cyttsp_power_on(ts);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: Error, power on failed!\n", __func__);
+		goto error_power_on;
+	}
+
+	/* Create the input device and register it. */
+	input_device = input_allocate_device();
+	if (!input_device) {
+		retval = -ENOMEM;
+		printk(KERN_ERR "%s: Error, failed to allocate input device\n",
+			__func__);
+		goto error_input_allocate_device;
+	}
+
+	ts->input = input_device;
+	input_device->name = ts->platform_data->name;
+	input_device->phys = ts->phys;
+	input_device->dev.parent = ts->pdev;
+	/* init the touch structures */
+	ts->num_prv_st_tch = CY_NTCH;
+	memset(ts->act_trk, CY_NTCH, sizeof(ts->act_trk));
+	memset(ts->prv_mt_pos, CY_NTCH, sizeof(ts->prv_mt_pos));
+	memset(ts->prv_mt_tch, CY_IGNR_TCH, sizeof(ts->prv_mt_tch));
+	memset(ts->prv_st_tch, CY_IGNR_TCH, sizeof(ts->prv_st_tch));
+
+	__set_bit(EV_SYN, input_device->evbit);
+	__set_bit(EV_KEY, input_device->evbit);
+	__set_bit(EV_ABS, input_device->evbit);
+	__set_bit(BTN_TOUCH, input_device->keybit);
+	__set_bit(BTN_2, input_device->keybit);
+	if (ts->platform_data->use_gestures)
+		__set_bit(BTN_3, input_device->keybit);
+
+	input_set_abs_params(input_device, ABS_X, 0, ts->platform_data->maxx,
+			     0, 0);
+	input_set_abs_params(input_device, ABS_Y, 0, ts->platform_data->maxy,
+			     0, 0);
+	input_set_abs_params(input_device, ABS_TOOL_WIDTH, 0,
+			     CY_LARGE_TOOL_WIDTH, 0, 0);
+	input_set_abs_params(input_device, ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
+	input_set_abs_params(input_device, ABS_HAT0X, 0,
+			     ts->platform_data->maxx, 0, 0);
+	input_set_abs_params(input_device, ABS_HAT0Y, 0,
+			     ts->platform_data->maxy, 0, 0);
+	if (ts->platform_data->use_gestures) {
+		input_set_abs_params(input_device, ABS_HAT1X, 0, CY_MAXZ,
+				     0, 0);
+		input_set_abs_params(input_device, ABS_HAT1Y, 0, CY_MAXZ,
+				     0, 0);
+	}
+	if (ts->platform_data->use_mt) {
+		input_set_abs_params(input_device, ABS_MT_POSITION_X, 0,
+				     ts->platform_data->maxx, 0, 0);
+		input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0,
+				     ts->platform_data->maxy, 0, 0);
+		input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR, 0,
+				     CY_MAXZ, 0, 0);
+		input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR, 0,
+				     CY_LARGE_TOOL_WIDTH, 0, 0);
+		if (ts->platform_data->use_trk_id)
+			input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
+					0, CY_NUM_TRK_ID, 0, 0);
+	}
+
+	if (ts->platform_data->use_virtual_keys)
+		input_set_capability(input_device, EV_KEY, KEY_PROG1);
+
+	retval = input_register_device(input_device);
+	if (retval) {
+		printk(KERN_ERR "%s: Error, failed to register input device\n",
+			__func__);
+		goto error_input_register_device;
+	}
+	DBG(printk(KERN_INFO "%s: Registered input device %s\n",
+		   __func__, input_device->name);)
+
+	/* Prepare our worker structure prior to setting up the timer ISR */
+	INIT_WORK(&ts->work, cyttsp_xy_worker_);
+
+	/* Timer or Interrupt setup */
+	if (ts->platform_data->use_timer) {
+		DBG(printk(KERN_INFO "%s: Setting up Timer\n", __func__);)
+		setup_timer(&ts->timer, cyttsp_timer, (unsigned long) ts);
+		mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
+	} else {
+		DBG(
+		printk(KERN_INFO "%s: Setting up Interrupt. Device name=%s\n",
+			__func__, input_device->name);)
+		retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   input_device->name, ts);
+
+		if (retval) {
+			printk(KERN_ERR "%s: Error, could not request irq\n",
+				__func__);
+			goto error_free_irq;
+		} else {
+			DBG(printk(KERN_INFO "%s: Interrupt=%d\n",
+				__func__, ts->irq);)
+		}
+	}
+	retval = device_create_file(pdev, &fwloader);
+	if (retval) {
+		printk(KERN_ERR "%s: Error, could not create attribute\n",
+			__func__);
+		goto device_create_error;
+	}
+	dev_set_drvdata(pdev, ts);
+	printk(KERN_INFO "%s: Successful.\n", __func__);
+	return ts;
+
+device_create_error:
+error_free_irq:
+	if (ts->irq >= 0)
+		free_irq(ts->irq, ts);
+	input_unregister_device(input_device);
+error_input_register_device:
+	input_free_device(input_device);
+error_input_allocate_device:
+error_power_on:
+	if (ts->platform_data->init)
+		ts->platform_data->init(0);
+error_init:
+	kfree(ts);
+error_alloc_data_failed:
+	return NULL;
+}
+
+/* registered in driver struct */
+void cyttsp_core_release(void *handle)
+{
+	struct cyttsp *ts = handle;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+	cancel_work_sync(&ts->work);
+	if (ts->platform_data->use_timer)
+		del_timer_sync(&ts->timer);
+	else
+		free_irq(ts->irq, ts);
+	input_unregister_device(ts->input);
+	input_free_device(ts->input);
+	if (ts->platform_data->init)
+		ts->platform_data->init(0);
+	kfree(ts);
+}
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
+MODULE_AUTHOR("Cypress");
+
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
new file mode 100755
index 0000000..25a732d
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -0,0 +1,49 @@
+/* Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx2xx and Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST241
+ * CY8CTMG240
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+
+
+#ifndef __CYTTSP_CORE_H__
+#define __CYTTSP_CORE_H__
+
+#include <linux/kernel.h>
+
+struct cyttsp_bus_ops {
+	s32 (*write)(void *handle, u8 addr, u8 length, const void *values);
+	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
+	s32 (*ext)(void *handle, void *values);
+};
+
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *pdev);
+void cyttsp_core_release(void *handle);
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle);
+int cyttsp_suspend(void *handle);
+#endif
+
+#endif /* __CYTTSP_CORE_H__ */
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100755
index 0000000..ef96105
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -0,0 +1,183 @@
+/* Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx2xx and Txx3xx parts with I2C interface.
+ * Supported parts include:
+ * CY8CTST241
+ * CY8CTMG240
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/cyttsp.h>
+#include "cyttsp_core.h"
+
+#define DBG(x)
+
+struct cyttsp_i2c {
+	struct cyttsp_bus_ops ops;
+	struct i2c_client *client;
+	void *ttsp_client;
+};
+
+static s32 ttsp_i2c_read_block_data(void *handle, u8 addr,
+	u8 length, void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	return i2c_smbus_read_i2c_block_data(ts->client,
+		addr, length, values);
+}
+
+static s32 ttsp_i2c_write_block_data(void *handle, u8 addr,
+	u8 length, const void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	return i2c_smbus_write_i2c_block_data(ts->client,
+		addr, length, values);
+}
+
+static s32 ttsp_i2c_tch_ext(void *handle, void *values)
+{
+	int retval = 0;
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+
+	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
+
+	/* Add custom touch extension handling code here */
+	/* set: retval < 0 for any returned system errors,
+		retval = 0 if normal touch handling is required,
+		retval > 0 if normal touch handling is *not* required */
+	if (!ts || !values)
+		retval = -EIO;
+
+	return retval;
+}
+static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct cyttsp_i2c *ts;
+	int retval;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	if (!i2c_check_functionality(client->adapter,
+		I2C_FUNC_SMBUS_READ_WORD_DATA))
+		return -EIO;
+
+	/* allocate and clear memory */
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (ts == NULL) {
+		printk(KERN_ERR "%s: Error, kzalloc.\n", __func__);
+		retval = -ENOMEM;
+		goto error_alloc_data_failed;
+	}
+
+	/* register driver_data */
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	ts->ops.write = ttsp_i2c_write_block_data;
+	ts->ops.read = ttsp_i2c_read_block_data;
+	ts->ops.ext = ttsp_i2c_tch_ext;
+
+	ts->ttsp_client = cyttsp_core_init(&ts->ops, &client->dev);
+	if (!ts->ttsp_client)
+		goto ttsp_core_err;
+
+	printk(KERN_INFO "%s: Successful registration %s\n",
+		__func__, CY_I2C_NAME);
+	return 0;
+
+ttsp_core_err:
+	kfree(ts);
+error_alloc_data_failed:
+	return retval;
+}
+
+
+/* registered in driver struct */
+static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+{
+	struct cyttsp_i2c *ts;
+
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+	ts = i2c_get_clientdata(client);
+	cyttsp_core_release(ts->ttsp_client);
+	kfree(ts);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	return cyttsp_suspend(dev_get_drvdata(&client->dev));
+}
+
+static int cyttsp_i2c_resume(struct i2c_client *client)
+{
+	return cyttsp_resume(dev_get_drvdata(&client->dev));
+}
+#endif
+
+static const struct i2c_device_id cyttsp_i2c_id[] = {
+	{ CY_I2C_NAME, 0 },  { }
+};
+
+static struct i2c_driver cyttsp_i2c_driver = {
+	.driver = {
+		.name = CY_I2C_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_i2c_probe,
+	.remove = __devexit_p(cyttsp_i2c_remove),
+	.id_table = cyttsp_i2c_id,
+#ifdef CONFIG_PM
+	.suspend = cyttsp_i2c_suspend,
+	.resume = cyttsp_i2c_resume,
+#endif
+};
+
+static int cyttsp_i2c_init(void)
+{
+	int retval;
+	retval = i2c_add_driver(&cyttsp_i2c_driver);
+	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product I2C "
+		"Touchscreen Driver (Built %s @ %s) returned %d\n",
+		 __func__, __DATE__, __TIME__, retval);
+
+	return retval;
+}
+
+static void cyttsp_i2c_exit(void)
+{
+	return i2c_del_driver(&cyttsp_i2c_driver);
+}
+
+module_init(cyttsp_i2c_init);
+module_exit(cyttsp_i2c_exit);
+
+MODULE_ALIAS("i2c:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100755
index 0000000..cb6432a
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -0,0 +1,339 @@
+/* Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx2xx and Txx3xx parts with SPI interface.
+ * Supported parts include:
+ * CY8CTST241
+ * CY8CTMG240
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/cyttsp.h>
+#include "cyttsp_core.h"
+
+#define DBG(x)
+
+#define CY_SPI_WR_OP      0x00 /* r/~w */
+#define CY_SPI_RD_OP      0x01
+#define CY_SPI_CMD_BYTES  4
+#define CY_SPI_SYNC_BYTES 2
+#define CY_SPI_SYNC_ACK1  0x62 /* from protocol v.2 */
+#define CY_SPI_SYNC_ACK2  0x9D /* from protocol v.2 */
+#define CY_SPI_SYNC_NACK  0x69
+#define CY_SPI_DATA_SIZE  64
+#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+#define CY_SPI_BITS_PER_WORD 8
+
+struct cyttsp_spi {
+	struct cyttsp_bus_ops ops;
+	struct spi_device *spi_client;
+	void *ttsp_client;
+	u8 wr_buf[CY_SPI_DATA_BUF_SIZE];
+	u8 rd_buf[CY_SPI_DATA_BUF_SIZE];
+};
+
+static void spi_complete(void *arg)
+{
+	complete(arg);
+}
+
+static int spi_sync_tmo(struct spi_device *spi, struct spi_message *message)
+{
+	DECLARE_COMPLETION_ONSTACK(done);
+	int status;
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	message->complete = spi_complete;
+	message->context = &done;
+	status = spi_async(spi, message);
+	if (status == 0) {
+		int ret = wait_for_completion_interruptible_timeout(&done, HZ);
+		if (!ret) {
+			printk(KERN_ERR "%s: timeout\n", __func__);
+			status = -EIO;
+		} else
+			status = message->status;
+	}
+	message->context = NULL;
+	return status;
+}
+
+static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts_spi,
+			    u8 reg, u8 *buf, int length)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer = { 0 };
+	u8 *wr_buf = ts_spi->wr_buf;
+	u8 *rd_buf = ts_spi->rd_buf;
+	int retval;
+	int i;
+	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
+
+	if (length > CY_SPI_DATA_SIZE) {
+		printk(KERN_ERR "%s: length %d is too big.\n",
+			__func__, length);
+		return -EINVAL;
+	}
+	DBG(printk(KERN_INFO "%s: OP=%s length=%d\n", __func__,
+		   op == CY_SPI_RD_OP ? "Read" : "Write", length);)
+
+	wr_buf[0] = 0x00; /* header byte 0 */
+	wr_buf[1] = 0xFF; /* header byte 1 */
+	wr_buf[2] = reg;  /* reg index */
+	wr_buf[3] = op;   /* r/~w */
+	if (op == CY_SPI_WR_OP)
+		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+	DBG(
+	if (op == CY_SPI_RD_OP)
+		memset(rd_buf, CY_SPI_SYNC_NACK, CY_SPI_DATA_BUF_SIZE);)
+	DBG(
+	for (i = 0; i < (length + CY_SPI_CMD_BYTES); i++) {
+		if ((op == CY_SPI_RD_OP) && (i < CY_SPI_CMD_BYTES))
+			printk(KERN_INFO "%s: wr[%d]:0x%02x\n",
+				__func__, i, wr_buf[i]);
+		if (op == CY_SPI_WR_OP)
+			printk(KERN_INFO "%s: wr[%d]:0x%02x\n",
+				__func__, i, wr_buf[i]);
+	})
+
+	xfer.tx_buf = wr_buf;
+	xfer.rx_buf = rd_buf;
+	xfer.len = length + CY_SPI_CMD_BYTES;
+
+	if ((op == CY_SPI_RD_OP) && (xfer.len < 32))
+		xfer.len += 1;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	retval = spi_sync_tmo(ts_spi->spi_client, &msg);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: spi_sync_tmo() error %d\n",
+			__func__, retval);
+		retval = 0;
+	}
+	if (op == CY_SPI_RD_OP) {
+		DBG(
+		for (i = 0; i < (length + CY_SPI_CMD_BYTES); i++)
+			printk(KERN_INFO "%s: rd[%d]:0x%02x\n",
+				__func__, i, rd_buf[i]);)
+
+		for (i = 0; i < (length + CY_SPI_CMD_BYTES - 1); i++) {
+			if ((rd_buf[i] != CY_SPI_SYNC_ACK1) ||
+				(rd_buf[i + 1] != CY_SPI_SYNC_ACK2)) {
+				continue;
+			}
+			if (i <= (CY_SPI_CMD_BYTES - 1)) {
+				memcpy(buf, (rd_buf + i + CY_SPI_SYNC_BYTES),
+					length);
+				return 0;
+			}
+		}
+		DBG(printk(KERN_INFO "%s: byte sync error\n", __func__);)
+		retval = 1;
+	}
+	return retval;
+}
+
+static int cyttsp_spi_xfer(u8 op, struct cyttsp_spi *ts,
+			    u8 reg, u8 *buf, int length)
+{
+	int tries;
+	int retval;
+	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
+
+	if (op == CY_SPI_RD_OP) {
+		for (tries = CY_NUM_RETRY; tries; tries--) {
+			retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+			if (retval == 0)
+				break;
+			else
+				msleep(10);
+		}
+	} else {
+		retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+	}
+	return retval;
+}
+
+static s32 ttsp_spi_read_block_data(void *handle, u8 addr,
+				    u8 length, void *data)
+{
+	int retval;
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+
+	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
+
+	retval = cyttsp_spi_xfer(CY_SPI_RD_OP, ts, addr, data, length);
+	if (retval < 0)
+		printk(KERN_ERR "%s: ttsp_spi_read_block_data failed\n",
+			__func__);
+
+	/* Do not print the above error if the data sync bytes were not found.
+	   This is a normal condition for the bootloader loader startup and need
+	   to retry until data sync bytes are found. */
+	if (retval > 0)
+		retval = -1;	/* now signal fail; so retry can be done */
+
+	return retval;
+}
+
+static s32 ttsp_spi_write_block_data(void *handle, u8 addr,
+				     u8 length, const void *data)
+{
+	int retval;
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+
+	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
+
+	retval = cyttsp_spi_xfer(CY_SPI_WR_OP, ts, addr, (void *)data, length);
+	if (retval < 0)
+		printk(KERN_ERR "%s: ttsp_spi_write_block_data failed\n",
+			__func__);
+
+	if (retval == -EIO)
+		return 0;
+	else
+		return retval;
+}
+
+static s32 ttsp_spi_tch_ext(void *handle, void *values)
+{
+	int retval = 0;
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+
+	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
+
+	/* Add custom touch extension handling code here */
+	/* set: retval < 0 for any returned system errors,
+		retval = 0 if normal touch handling is required,
+		retval > 0 if normal touch handling is *not* required */
+	if (!ts || !values)
+		retval = -EIO;
+
+	return retval;
+}
+
+static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts_spi;
+	int retval;
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+
+	/* Set up SPI*/
+	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+	spi->mode = SPI_MODE_0;
+	retval = spi_setup(spi);
+	if (retval < 0) {
+		printk(KERN_ERR "%s: SPI setup error %d\n", __func__, retval);
+		return retval;
+	}
+	ts_spi = kzalloc(sizeof(*ts_spi), GFP_KERNEL);
+	if (ts_spi == NULL) {
+		printk(KERN_ERR "%s: Error, kzalloc\n", __func__);
+		retval = -ENOMEM;
+		goto error_alloc_data_failed;
+	}
+	ts_spi->spi_client = spi;
+	dev_set_drvdata(&spi->dev, ts_spi);
+	ts_spi->ops.write = ttsp_spi_write_block_data;
+	ts_spi->ops.read = ttsp_spi_read_block_data;
+	ts_spi->ops.ext = ttsp_spi_tch_ext;
+
+	ts_spi->ttsp_client = cyttsp_core_init(&ts_spi->ops, &spi->dev);
+	if (!ts_spi->ttsp_client)
+		goto ttsp_core_err;
+	printk(KERN_INFO "%s: Successful registration %s\n",
+	       __func__, CY_SPI_NAME);
+
+	return 0;
+
+ttsp_core_err:
+	kfree(ts_spi);
+error_alloc_data_failed:
+	return retval;
+}
+
+/* registered in driver struct */
+static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts_spi = dev_get_drvdata(&spi->dev);
+	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
+	cyttsp_core_release(ts_spi->ttsp_client);
+	kfree(ts_spi);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	return cyttsp_suspend(dev_get_drvdata(&spi->dev));
+}
+
+static int cyttsp_spi_resume(struct spi_device *spi)
+{
+	return cyttsp_resume(dev_get_drvdata(&spi->dev));
+}
+#endif
+
+static struct spi_driver cyttsp_spi_driver = {
+	.driver = {
+		.name = CY_SPI_NAME,
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_spi_probe,
+	.remove = __devexit_p(cyttsp_spi_remove),
+#ifdef CONFIG_PM
+	.suspend = cyttsp_spi_suspend,
+	.resume = cyttsp_spi_resume,
+#endif
+};
+
+static int __init cyttsp_spi_init(void)
+{
+	int err;
+
+	err = spi_register_driver(&cyttsp_spi_driver);
+	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product SPI "
+		"Touchscreen Driver (Built %s @ %s) returned %d\n",
+		 __func__, __DATE__, __TIME__, err);
+
+	return err;
+}
+module_init(cyttsp_spi_init);
+
+static void __exit cyttsp_spi_exit(void)
+{
+	spi_unregister_driver(&cyttsp_spi_driver);
+	printk(KERN_INFO "%s: module exit\n", __func__);
+}
+module_exit(cyttsp_spi_exit);
+
+MODULE_ALIAS("spi:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+
diff --git a/include/linux/cyttsp.h b/include/linux/cyttsp.h
new file mode 100755
index 0000000..b2a289b
--- /dev/null
+++ b/include/linux/cyttsp.h
@@ -0,0 +1,104 @@
+/* Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx2xx and Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST241
+ * CY8CTMG240
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+#include <linux/input.h>
+
+#ifndef _CYTTSP_H_
+#define _CYTTSP_H_
+
+#include <linux/input.h>
+
+#define CY_SPI_NAME "cyttsp-spi"
+#define CY_I2C_NAME "cyttsp-i2c"
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT 0x00
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT 0xFF
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT 0x0A
+/*
+ *defines for Gen2 (Txx2xx); Gen3 (Txx3xx)
+ * use these defines to set cyttsp_platform_data.gen in board config file
+ */
+enum cyttsp_gen {
+	CY_GEN2,
+	CY_GEN3,
+};
+/*
+ * Active distance in pixels for a gesture to be reported
+ * if set to 0, then all gesture movements are reported
+ * Valid range is 0 - 15
+ */
+#define CY_ACT_DIST_DFLT 8
+#define CY_ACT_DIST CY_ACT_DIST_DFLT
+/* max num retries to read touch data */
+#define CY_NUM_RETRY 4
+
+enum cyttsp_gest {
+	CY_GEST_GRP_NONE = 0,
+	CY_GEST_GRP1 =	0x10,
+	CY_GEST_GRP2 = 0x20,
+	CY_GEST_GRP3 = 0x40,
+	CY_GEST_GRP4 = 0x80,
+};
+
+enum cyttsp_powerstate {
+	CY_IDLE_STATE,
+	CY_ACTIVE_STATE,
+	CY_LOW_PWR_STATE,
+	CY_SLEEP_STATE,
+};
+
+struct cyttsp_platform_data {
+	u32 maxx;
+	u32 maxy;
+	u32 flags;
+	enum cyttsp_gen gen;
+	unsigned use_st:1;
+	unsigned use_mt:1;
+	unsigned use_trk_id:1;
+	unsigned use_hndshk:1;
+	unsigned use_timer:1;
+	unsigned use_sleep:1;
+	unsigned use_gestures:1;
+	unsigned use_load_file:1;
+	unsigned use_force_fw_update:1;
+	unsigned use_virtual_keys:1;
+	enum cyttsp_powerstate power_state;
+	u8 gest_set;
+	u8 act_intrvl;  /* Active refresh interval; ms */
+	u8 tch_tmout;   /* Active touch timeout; ms */
+	u8 lp_intrvl;   /* Low power refresh interval; ms */
+	int (*wakeup)(void);
+	int (*init)(int on_off);
+	void (*mt_sync)(struct input_dev *);
+	char *name;
+	s16 irq_gpio;
+};
+
+#endif /* _CYTTSP_H_ */
-- 
1.6.3.3


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-05 18:12 ` [PATCH] i2c: cyttsp i2c and spi " Kevin McNeely
@ 2010-08-05 20:45   ` Trilok Soni
  2010-08-05 21:07     ` Dmitry Torokhov
  2010-08-07  0:52     ` Kevin McNeely
  2010-08-05 23:06   ` Henrik Rydberg
  2010-08-06  9:06   ` Trilok Soni
  2 siblings, 2 replies; 70+ messages in thread
From: Trilok Soni @ 2010-08-05 20:45 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Fred, Samuel Ortiz, Eric Miao,
	Ben Dooks, Simtec Linux Team, Todd Fischer, Arnaud Patard,
	Sascha Hauer, Henrik Rydberg, linux-input, linux-kernel

Hi Kevin,

On 8/5/2010 11:42 PM, Kevin McNeely wrote:
> From: Fred <fwk@ubuntu.linuxcertified.com>
> 

E-mail address is is wrong again it seems. Please fix. 

You may want to divide this whole patch into three patches:

1. core driver
2. i2c driver
3. spi driver

> This is a new touchscreen driver for the Cypress Semiconductor
> cyttsp family of devices.  This updated driver is for both the i2c and spi
> versions of the devices. The driver code consists of common core code for
> both i2c and spi driver.  This submission is in response to review comments
> from the initial submission.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>
> ---
>  drivers/input/touchscreen/Kconfig            |   33 +
>  drivers/input/touchscreen/Makefile           |    3 +
>  drivers/input/touchscreen/cyttsp_board-xxx.c |  110 ++
>  drivers/input/touchscreen/cyttsp_core.c      | 1778 ++++++++++++++++++++++++++
>  drivers/input/touchscreen/cyttsp_core.h      |   49 +
>  drivers/input/touchscreen/cyttsp_i2c.c       |  183 +++
>  drivers/input/touchscreen/cyttsp_spi.c       |  339 +++++
>  include/linux/cyttsp.h                       |  104 ++
>  8 files changed, 2599 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/input/touchscreen/cyttsp_board-xxx.c
>  create mode 100755 drivers/input/touchscreen/cyttsp_core.c
>  create mode 100755 drivers/input/touchscreen/cyttsp_core.h
>  create mode 100755 drivers/input/touchscreen/cyttsp_i2c.c
>  create mode 100755 drivers/input/touchscreen/cyttsp_spi.c
>  create mode 100755 include/linux/cyttsp.h

File modes are wrong.


> 
> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 3b9d5e2..b923379 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -603,4 +603,37 @@ config TOUCHSCREEN_TPS6507X
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called tps6507x_ts.
>  
> +config TOUCHSCREEN_CYTTSP_I2C
> +	default n

default n is not required.

> +	tristate "Cypress TTSP i2c touchscreen"
> +	depends on I2C
> +	help
> +	  Say Y here if you have a Cypress TTSP touchscreen
> +	  connected to your system's i2c bus.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called cyttsp_i2c.
> +
> +config TOUCHSCREEN_CYTTSP_SPI
> +	default n

Ditto.

> +	tristate "Cypress TTSP spi touchscreen"
> +	depends on SPI_MASTER
> +	help
> +	  Say Y here if you have a Cypress TTSP touchscreen
> +	  connected to your system's spi bus.
> +
> +	  If unsure, say N.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called cyttsp_spi.
> +
> +config TOUCHSCREEN_CYTTSP_CORE
> +	default y

We don't want anything to be default y unless it is curing a cancer.

> diff --git a/drivers/input/touchscreen/cyttsp_board-xxx.c b/drivers/input/touchscreen/cyttsp_board-xxx.c

This file is good as example only but not for check in. This is a board specific code and the board-xxx.c
code in appropriate arch will carry this code. Please remove this file from the patch.

> diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
> new file mode 100755
> index 0000000..95019e9
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp_core.c
> @@ -0,0 +1,1778 @@
> +/* Core Source for:
> + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
> + * For use with Cypress Txx2xx and Txx3xx parts.
> + * Supported parts include:
> + * CY8CTST241
> + * CY8CTMG240
> + * CY8CTST341
> + * CY8CTMA340
> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
> + *
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/input.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/timer.h>
> +#include <linux/workqueue.h>
> +#include <linux/byteorder/generic.h>
> +#include <linux/bitops.h>
> +#include <linux/cyttsp.h>
> +#include <linux/ctype.h>
> +#include "cyttsp_core.h"
> +
> +#define DBG(x)
> +
> +/* rely on kernel input.h to define Multi-Touch capability */
> +#ifndef ABS_MT_TRACKING_ID
> +/* define only if not defined already by system; */
> +/* value based on linux kernel 2.6.30.10 */
> +#define ABS_MT_TRACKING_ID (ABS_MT_BLOB_ID + 1)
> +#endif /* ABS_MT_TRACKING_ID */

We always support and base our code from latest kernel only. Please remove the code
which relies on supporting older kernels. 

> +
> +#define	TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(28))
> +/* Bootloader File 0 offset */
> +#define CY_BL_FILE0       0x00
> +/* Bootloader command directive */
> +#define CY_BL_CMD         0xFF
> +/* Bootloader Enter Loader mode */
> +#define CY_BL_ENTER       0x38
> +/* Bootloader Write a Block */
> +#define CY_BL_WRITE_BLK   0x39
> +/* Bootloader Terminate Loader mode */
> +#define CY_BL_TERMINATE   0x3B
> +/* Bootloader Exit and Verify Checksum command */
> +#define CY_BL_EXIT        0xA5
> +/* Bootloader default keys */
> +#define CY_BL_KEY0 0
> +#define CY_BL_KEY1 1
> +#define CY_BL_KEY2 2
> +#define CY_BL_KEY3 3
> +#define CY_BL_KEY4 4
> +#define CY_BL_KEY5 5
> +#define CY_BL_KEY6 6
> +#define CY_BL_KEY7 7
> +
> +#define CY_DIFF(m, n)               ((m) != (n))

And why such macro is required? Why can't we just do "if (i != j)"?

> +
> +/* TTSP Bootloader Register Map interface definition */
> +#define CY_BL_CHKSUM_OK 0x01
> +struct cyttsp_bootloader_data {
> +	u8 bl_file;
> +	u8 bl_status;
> +	u8 bl_error;
> +	u8 blver_hi;
> +	u8 blver_lo;
> +	u8 bld_blver_hi;
> +	u8 bld_blver_lo;
> +	u8 ttspver_hi;
> +	u8 ttspver_lo;
> +	u8 appid_hi;
> +	u8 appid_lo;
> +	u8 appver_hi;
> +	u8 appver_lo;
> +	u8 cid_0;
> +	u8 cid_1;
> +	u8 cid_2;
> +};
> +
> +#define cyttsp_wake_data cyttsp_xydata

Why we need to such assignments and introduce these kind of macros? I don't think it is necessary.

> +
> +struct cyttsp {
> +	struct device *pdev;

Most of the time kernel people understands "pdev == platform device and not just device", so better rename this variable
to "dev" only.

> +	int irq;
> +	struct input_dev *input;
> +	struct work_struct work;
> +	struct timer_list timer;
> +	struct mutex mutex;
> +	char phys[32];
> +	struct cyttsp_platform_data *platform_data;
> +	struct cyttsp_bootloader_data bl_data;
> +	struct cyttsp_sysinfo_data sysinfo_data;
> +	u8 num_prv_st_tch;
> +	u16 act_trk[CY_NUM_TRK_ID];
> +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> +	struct cyttsp_bus_ops *bus_ops;
> +	unsigned fw_loader_mode:1;
> +	unsigned suspended:1;
> +};
> +
> +struct cyttsp_track_data {
> +	u8 prv_tch;
> +	u8 cur_tch;
> +	u16 tmp_trk[CY_NUM_MT_TCH_ID];
> +	u16 snd_trk[CY_NUM_MT_TCH_ID];
> +	u16 cur_trk[CY_NUM_TRK_ID];
> +	u16 cur_st_tch[CY_NUM_ST_TCH_ID];
> +	u16 cur_mt_tch[CY_NUM_MT_TCH_ID];
> +	/* if NOT CY_USE_TRACKING_ID then only */
> +	/* uses CY_NUM_MT_TCH_ID positions */
> +	u16 cur_mt_pos[CY_NUM_TRK_ID][2];
> +	/* if NOT CY_USE_TRACKING_ID then only */
> +	/* uses CY_NUM_MT_TCH_ID positions */
> +	u8 cur_mt_z[CY_NUM_TRK_ID];
> +	u8 tool_width;
> +	u16 st_x1;
> +	u16 st_y1;
> +	u8 st_z1;
> +	u16 st_x2;
> +	u16 st_y2;
> +	u8 st_z2;
> +};
> +
> +static const u8 bl_cmd[] = {
> +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> +	CY_BL_KEY6, CY_BL_KEY7
> +};
> +
> +#define LOCK(m) do { \
> +	DBG(printk(KERN_INFO "%s: lock\n", __func__);) \
> +	mutex_lock(&(m)); \
> +} while (0);
> +
> +#define UNLOCK(m) do { \
> +	DBG(printk(KERN_INFO "%s: unlock\n", __func__);) \
> +	mutex_unlock(&(m)); \
> +} while (0);

Un-necessary debug macros and abstractions. This is not allowed. Please use mutext_lock and unlock
APIs directly wherever they are required.

> +
> +DBG(
> +static void print_data_block(const char *func, u8 command,
> +			u8 length, void *data)
> +{
> +	char buf[1024];
> +	unsigned buf_len = sizeof(buf);
> +	char *p = buf;
> +	int i;
> +	int l;
> +
> +	l = snprintf(p, buf_len, "cmd 0x%x: ", command);
> +	buf_len -= l;
> +	p += l;
> +	for (i = 0; i < length && buf_len; i++, p += l, buf_len -= l)
> +		l = snprintf(p, buf_len, "%02x ", *((char *)data + i));
> +	printk(KERN_DEBUG "%s: %s\n", func, buf);
> +})

Please don't do like DBG(...) like things. As it is strictly for debugging purpose only
please remove this function from the code itself. Developer in need of such debugging routines
will write down their own when they sit for debugging the problem. I don't see any need
of such debugging helpers in the mainlined version of the driver.

> +
> +static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
> +	u8 length, void *buf)
> +{
> +	int rc;
> +	int tries;
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> +
> +	if (!buf || !length) {
> +		printk(KERN_ERR "%s: Error, buf:%s len:%u\n",
> +				__func__, !buf ? "NULL" : "OK", length);
> +		return -EIO;
> +	}
> +
> +	for (tries = 0, rc = 1; tries < CY_NUM_RETRY && rc; tries++)
> +		rc = ts->bus_ops->read(ts->bus_ops, command, length, buf);
> +
> +	if (rc < 0)
> +		printk(KERN_ERR "%s: error %d\n", __func__, rc);
> +	DBG(print_data_block(__func__, command, length, buf);)

Please use dev_dbg(...) or pr_debug(...) macros directly instead of putting
them under DBG(...). 

It is better you remove DBG(..) from whole driver and replace them with
dev_dbg(...) if you have device pointer or use pr_debug(...).

> +
> +static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
> +{
> +	int rc;
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)

Un-necessary debug statements. Such statements should be removed from the driver.

> +
> +/* ************************************************************************
> + * The cyttsp_xy_worker function reads the XY coordinates and sends them to
> + * the input layer.  It is scheduled from the interrupt (or timer).
> + * *************************************************************************/
> +void handle_single_touch(struct cyttsp_xydata *xy, struct cyttsp_track_data *t,
> +			 struct cyttsp *ts)
> +{

functions should be "static". I would leave a decision to Dmitry if he wants the driver
to support old single touch protocol hacked up with HAT_xx bits so that driver can support
two touches with the old single touch protocol itself. 

I would prefer not to support this single touch because we are hacking up this
because the userspace frameworks are not converted or supporting the new MT based protocols.

> +
> +void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
> +{

static please.

> +
> +void cyttsp_xy_worker(struct cyttsp *ts)
> +{

static please.

> +
> +	DBG(
> +	if (trc.cur_tch) {
> +		unsigned i;
> +		u8 *pdata = (u8 *)&xy_data;
> +
> +		printk(KERN_INFO "%s: TTSP data_pack: ", __func__);
> +		for (i = 0; i < sizeof(struct cyttsp_xydata); i++)
> +			printk(KERN_INFO "[%d]=0x%x ", i, pdata[i]);
> +		printk(KERN_INFO "\n");
> +	})

I would really like to remove such DBG formatted code.

> +
> +	/* Determine if display is tilted */
> +	tilt = !!FLIP_DATA(ts->platform_data->flags);
> +	/* Check for switch in origin */
> +	rev_x = !!REVERSE_X(ts->platform_data->flags);
> +	rev_y = !!REVERSE_Y(ts->platform_data->flags);
> +

...

> +
> +	/* update platform data for the current multi-touch information */
> +	memcpy(ts->act_trk, trc.cur_trk, CY_NUM_TRK_ID);
> +
> +exit_xy_worker:
> +	DBG(printk(KERN_INFO"%s: finished.\n", __func__);)
> +	return;

Do you need this return statment?

> +}
> +
> +/* ************************************************************************
> + * ISR function. This function is general, initialized in drivers init
> + * function and disables further IRQs until this IRQ is processed in worker.
> + * *************************************************************************/
> +static irqreturn_t cyttsp_irq(int irq, void *handle)
> +{
> +	struct cyttsp *ts = (struct cyttsp *)handle;

Casting is not required when the source is void *.

> +
> +	DBG(printk(KERN_INFO"%s: Got IRQ!\n", __func__);)

Un-necessary debug statements.

> +	cyttsp_xy_worker(ts);
> +	return IRQ_HANDLED;
> +}
> +
> +/* schedulable worker entry for timer polling method */
> +void cyttsp_xy_worker_(struct work_struct *work)
> +{
> +	struct cyttsp *ts = container_of(work, struct cyttsp, work);
> +	cyttsp_xy_worker(ts);
> +}

I would really prefer that you remove the polling method from this code as it will simplify
a code lot. We can delete the whole workqueue because as you will be using request_threaded_irq(...),
you will not need any workqueue.

> +
> +/* Timer function used as touch interrupt generator for polling method */
> +static void cyttsp_timer(unsigned long handle)
> +{
> +	struct cyttsp *ts = (struct cyttsp *)handle;
> +
> +	DBG(printk(KERN_INFO"%s: TTSP timer event!\n", __func__);)
> +	/* schedule motion signal handling */
> +	if (!work_pending(&ts->work))
> +		schedule_work(&ts->work);
> +	mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
> +	return;
> +}

I don't see any need of this timer. Better remove the polling method all together to simplify the code.
Only support interrupt based approach only. 


> +
> +
> +/* ************************************************************************
> + * Probe initialization functions
> + * ************************************************************************ */
> +static int cyttsp_load_bl_regs(struct cyttsp *ts)
> +{
> +	int retval;
> +
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> +
> +	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
> +				sizeof(ts->bl_data), &(ts->bl_data));
> +
> +	if (retval < 0) {
> +		DBG(printk(KERN_INFO "%s: Failed reading block data, err:%d\n",
> +			__func__, retval);)
> +		goto fail;
> +	}
> +
> +	DBG({
> +	      int i;
> +	      u8 *bl_data = (u8 *)&(ts->bl_data);
> +	      for (i = 0; i < sizeof(struct cyttsp_bootloader_data); i++)
> +			printk(KERN_INFO "%s bl_data[%d]=0x%x\n",
> +				__func__, i, bl_data[i]);
> +	})

Better remove such debug code.

> +
> +	return 0;
> +fail:
> +	return retval;
> +}

...

> +
> +static ssize_t firmware_write(struct kobject *kobj,
> +				struct bin_attribute *bin_attr,
> +				char *buf, loff_t pos, size_t size)
> +{
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct cyttsp *ts = dev_get_drvdata(dev);
> +	LOCK(ts->mutex);
> +	DBG({
> +		char str[128];
> +		char *p = str;
> +		int i;
> +		for (i = 0; i < size; i++, p += 2)
> +			sprintf(p, "%02x", (unsigned char)buf[i]);
> +		printk(KERN_DEBUG "%s: size %d, pos %ld payload %s\n",
> +		       __func__, size, (long)pos, str);
> +	})
> +	ttsp_write_block_data(ts, CY_REG_BASE, size, buf);
> +	UNLOCK(ts->mutex);
> +	return size;
> +}
> +
> +static ssize_t firmware_read(struct kobject *kobj,
> +	struct bin_attribute *ba,
> +	char *buf, loff_t pos, size_t size)
> +{
> +	int count = 0;
> +	struct device *dev = container_of(kobj, struct device, kobj);
> +	struct cyttsp *ts = dev_get_drvdata(dev);
> +
> +	LOCK(ts->mutex);
> +	if (!ts->fw_loader_mode)
> +		goto exit;
> +	if (!cyttsp_load_bl_regs(ts)) {
> +		*(unsigned short *)buf = ts->bl_data.bl_status << 8 |
> +			ts->bl_data.bl_error;
> +		count = sizeof(unsigned short);
> +	} else {
> +		printk(KERN_ERR "%s: error reading status\n", __func__);
> +		count = 0;
> +	}
> +exit:
> +	UNLOCK(ts->mutex);
> +	return count;
> +}

This kind of custom interface may not be allowed in the kernel driver. Please use
request_firmware(...) call based interface to support firmware loading.

> +
> +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *pdev)
> +{
> +	struct input_dev *input_device;
> +	struct cyttsp *ts;
> +	int retval = 0;
> +
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> +
> +	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> +	if (ts == NULL) {
> +		printk(KERN_ERR "%s: Error, kzalloc\n", __func__);
> +		goto error_alloc_data_failed;
> +	}
> +	mutex_init(&ts->mutex);
> +	ts->pdev = pdev;
> +	ts->platform_data = pdev->platform_data;
> +	ts->bus_ops = bus_ops;
> +
> +	if (ts->platform_data->init)
> +		retval = ts->platform_data->init(1);
> +	if (retval) {
> +		printk(KERN_ERR "%s: platform init failed!\n", __func__);
> +		goto error_init;
> +	}
> +
> +	if (ts->platform_data->use_timer)
> +		ts->irq = -1;
> +	else
> +		ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
> +
> +	retval = cyttsp_power_on(ts);
> +	if (retval < 0) {
> +		printk(KERN_ERR "%s: Error, power on failed!\n", __func__);
> +		goto error_power_on;
> +	}
> +
> +	/* Create the input device and register it. */
> +	input_device = input_allocate_device();
> +	if (!input_device) {
> +		retval = -ENOMEM;
> +		printk(KERN_ERR "%s: Error, failed to allocate input device\n",
> +			__func__);
> +		goto error_input_allocate_device;
> +	}
> +
> +	ts->input = input_device;
> +	input_device->name = ts->platform_data->name;
> +	input_device->phys = ts->phys;
> +	input_device->dev.parent = ts->pdev;
> +	/* init the touch structures */
> +	ts->num_prv_st_tch = CY_NTCH;
> +	memset(ts->act_trk, CY_NTCH, sizeof(ts->act_trk));
> +	memset(ts->prv_mt_pos, CY_NTCH, sizeof(ts->prv_mt_pos));
> +	memset(ts->prv_mt_tch, CY_IGNR_TCH, sizeof(ts->prv_mt_tch));
> +	memset(ts->prv_st_tch, CY_IGNR_TCH, sizeof(ts->prv_st_tch));
> +
> +	__set_bit(EV_SYN, input_device->evbit);
> +	__set_bit(EV_KEY, input_device->evbit);
> +	__set_bit(EV_ABS, input_device->evbit);
> +	__set_bit(BTN_TOUCH, input_device->keybit);
> +	__set_bit(BTN_2, input_device->keybit);
> +	if (ts->platform_data->use_gestures)
> +		__set_bit(BTN_3, input_device->keybit);
> +
> +	input_set_abs_params(input_device, ABS_X, 0, ts->platform_data->maxx,
> +			     0, 0);
> +	input_set_abs_params(input_device, ABS_Y, 0, ts->platform_data->maxy,
> +			     0, 0);
> +	input_set_abs_params(input_device, ABS_TOOL_WIDTH, 0,
> +			     CY_LARGE_TOOL_WIDTH, 0, 0);
> +	input_set_abs_params(input_device, ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
> +	input_set_abs_params(input_device, ABS_HAT0X, 0,
> +			     ts->platform_data->maxx, 0, 0);
> +	input_set_abs_params(input_device, ABS_HAT0Y, 0,
> +			     ts->platform_data->maxy, 0, 0);
> +	if (ts->platform_data->use_gestures) {
> +		input_set_abs_params(input_device, ABS_HAT1X, 0, CY_MAXZ,
> +				     0, 0);
> +		input_set_abs_params(input_device, ABS_HAT1Y, 0, CY_MAXZ,
> +				     0, 0);
> +	}
> +	if (ts->platform_data->use_mt) {
> +		input_set_abs_params(input_device, ABS_MT_POSITION_X, 0,
> +				     ts->platform_data->maxx, 0, 0);
> +		input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0,
> +				     ts->platform_data->maxy, 0, 0);
> +		input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR, 0,
> +				     CY_MAXZ, 0, 0);
> +		input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR, 0,
> +				     CY_LARGE_TOOL_WIDTH, 0, 0);
> +		if (ts->platform_data->use_trk_id)
> +			input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
> +					0, CY_NUM_TRK_ID, 0, 0);
> +	}
> +
> +	if (ts->platform_data->use_virtual_keys)
> +		input_set_capability(input_device, EV_KEY, KEY_PROG1);
> +
> +	retval = input_register_device(input_device);
> +	if (retval) {
> +		printk(KERN_ERR "%s: Error, failed to register input device\n",
> +			__func__);
> +		goto error_input_register_device;
> +	}
> +	DBG(printk(KERN_INFO "%s: Registered input device %s\n",
> +		   __func__, input_device->name);)
> +
> +	/* Prepare our worker structure prior to setting up the timer ISR */
> +	INIT_WORK(&ts->work, cyttsp_xy_worker_);
> +
> +	/* Timer or Interrupt setup */
> +	if (ts->platform_data->use_timer) {
> +		DBG(printk(KERN_INFO "%s: Setting up Timer\n", __func__);)
> +		setup_timer(&ts->timer, cyttsp_timer, (unsigned long) ts);
> +		mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
> +	} else {
> +		DBG(
> +		printk(KERN_INFO "%s: Setting up Interrupt. Device name=%s\n",
> +			__func__, input_device->name);)
> +		retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
> +				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> +				   input_device->name, ts);
> +
> +		if (retval) {
> +			printk(KERN_ERR "%s: Error, could not request irq\n",
> +				__func__);
> +			goto error_free_irq;
> +		} else {
> +			DBG(printk(KERN_INFO "%s: Interrupt=%d\n",
> +				__func__, ts->irq);)
> +		}
> +	}
> +	retval = device_create_file(pdev, &fwloader);
> +	if (retval) {
> +		printk(KERN_ERR "%s: Error, could not create attribute\n",
> +			__func__);
> +		goto device_create_error;
> +	}
> +	dev_set_drvdata(pdev, ts);
> +	printk(KERN_INFO "%s: Successful.\n", __func__);
> +	return ts;
> +
> +device_create_error:
> +error_free_irq:
> +	if (ts->irq >= 0)
> +		free_irq(ts->irq, ts);
> +	input_unregister_device(input_device);
> +error_input_register_device:
> +	input_free_device(input_device);
> +error_input_allocate_device:
> +error_power_on:
> +	if (ts->platform_data->init)
> +		ts->platform_data->init(0);
> +error_init:
> +	kfree(ts);
> +error_alloc_data_failed:
> +	return NULL;
> +}
> +
EXPORT_SYMBOL_GPL(...)?

> +/* registered in driver struct */
> +void cyttsp_core_release(void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> +	cancel_work_sync(&ts->work);
> +	if (ts->platform_data->use_timer)
> +		del_timer_sync(&ts->timer);
> +	else
> +		free_irq(ts->irq, ts);
> +	input_unregister_device(ts->input);
> +	input_free_device(ts->input);

No need of input_free_device after input_unregister_device.

> +	if (ts->platform_data->init)
> +		ts->platform_data->init(0);
> +	kfree(ts);
> +}

EXPORT_SYMBOL_GPL(...)?

> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
> +MODULE_AUTHOR("Cypress");
> +


> diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
> new file mode 100755
> index 0000000..ef96105
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp_i2c.c
> @@ -0,0 +1,183 @@
> +/* Source for:
> + * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
> + * For use with Cypress Txx2xx and Txx3xx parts with I2C interface.
> + * Supported parts include:
> + * CY8CTST241
> + * CY8CTMG240
> + * CY8CTST341
> + * CY8CTMA340
> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
> + *
> + */
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/cyttsp.h>
> +#include "cyttsp_core.h"
> +
> +#define DBG(x)
> +
> +struct cyttsp_i2c {
> +	struct cyttsp_bus_ops ops;
> +	struct i2c_client *client;
> +	void *ttsp_client;
> +};
> +
> +static s32 ttsp_i2c_read_block_data(void *handle, u8 addr,
> +	u8 length, void *values)
> +{
> +	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
> +	return i2c_smbus_read_i2c_block_data(ts->client,
> +		addr, length, values);
> +}
> +
> +static s32 ttsp_i2c_write_block_data(void *handle, u8 addr,
> +	u8 length, const void *values)
> +{
> +	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
> +	return i2c_smbus_write_i2c_block_data(ts->client,
> +		addr, length, values);
> +}
> +
> +static s32 ttsp_i2c_tch_ext(void *handle, void *values)
> +{
> +	int retval = 0;
> +	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
> +
> +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
> +
> +	/* Add custom touch extension handling code here */
> +	/* set: retval < 0 for any returned system errors,
> +		retval = 0 if normal touch handling is required,
> +		retval > 0 if normal touch handling is *not* required */
> +	if (!ts || !values)
> +		retval = -EIO;
> +
> +	return retval;
> +}
> +static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
> +	const struct i2c_device_id *id)
> +{
> +	struct cyttsp_i2c *ts;
> +	int retval;
> +
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> +
> +	if (!i2c_check_functionality(client->adapter,
> +		I2C_FUNC_SMBUS_READ_WORD_DATA))
> +		return -EIO;
> +
> +	/* allocate and clear memory */
> +	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> +	if (ts == NULL) {
> +		printk(KERN_ERR "%s: Error, kzalloc.\n", __func__);
> +		retval = -ENOMEM;
> +		goto error_alloc_data_failed;
> +	}
> +
> +	/* register driver_data */
> +	ts->client = client;
> +	i2c_set_clientdata(client, ts);
> +	ts->ops.write = ttsp_i2c_write_block_data;
> +	ts->ops.read = ttsp_i2c_read_block_data;
> +	ts->ops.ext = ttsp_i2c_tch_ext;
> +
> +	ts->ttsp_client = cyttsp_core_init(&ts->ops, &client->dev);
> +	if (!ts->ttsp_client)
> +		goto ttsp_core_err;
> +
> +	printk(KERN_INFO "%s: Successful registration %s\n",
> +		__func__, CY_I2C_NAME);
> +	return 0;
> +
> +ttsp_core_err:
> +	kfree(ts);
> +error_alloc_data_failed:
> +	return retval;
> +}
> +
> +
> +/* registered in driver struct */
> +static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
> +{
> +	struct cyttsp_i2c *ts;
> +
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> +	ts = i2c_get_clientdata(client);
> +	cyttsp_core_release(ts->ttsp_client);
> +	kfree(ts);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int cyttsp_i2c_suspend(struct i2c_client *client, pm_message_t message)
> +{
> +	return cyttsp_suspend(dev_get_drvdata(&client->dev));
> +}
> +
> +static int cyttsp_i2c_resume(struct i2c_client *client)
> +{
> +	return cyttsp_resume(dev_get_drvdata(&client->dev));
> +}
> +#endif
> +
> +static const struct i2c_device_id cyttsp_i2c_id[] = {
> +	{ CY_I2C_NAME, 0 },  { }
> +};
> +
> +static struct i2c_driver cyttsp_i2c_driver = {
> +	.driver = {
> +		.name = CY_I2C_NAME,
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = cyttsp_i2c_probe,
> +	.remove = __devexit_p(cyttsp_i2c_remove),
> +	.id_table = cyttsp_i2c_id,
> +#ifdef CONFIG_PM
> +	.suspend = cyttsp_i2c_suspend,
> +	.resume = cyttsp_i2c_resume,
> +#endif
> +};
> +
> +static int cyttsp_i2c_init(void)
> +{

Please add __init like

static int __init cyttsp_i2c_init(void)

> +	int retval;
> +	retval = i2c_add_driver(&cyttsp_i2c_driver);
> +	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product I2C "
> +		"Touchscreen Driver (Built %s @ %s) returned %d\n",
> +		 __func__, __DATE__, __TIME__, retval);
> +
> +	return retval;
> +}
> +
> +static void cyttsp_i2c_exit(void)

__exit

> +{
> +	return i2c_del_driver(&cyttsp_i2c_driver);
> +}
> +
> +module_init(cyttsp_i2c_init);
> +module_exit(cyttsp_i2c_exit);
> +
> +MODULE_ALIAS("i2c:cyttsp");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
> +MODULE_AUTHOR("Cypress");
> +MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
> diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
> new file mode 100755
> index 0000000..cb6432a
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp_spi.c

I will comment on spi driver interface later.

---Trilok Soni

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-05 20:45   ` Trilok Soni
@ 2010-08-05 21:07     ` Dmitry Torokhov
  2010-08-07  0:39       ` Kevin McNeely
  2010-08-07  0:52     ` Kevin McNeely
  1 sibling, 1 reply; 70+ messages in thread
From: Dmitry Torokhov @ 2010-08-05 21:07 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Kevin McNeely, David Brown, Fred, Samuel Ortiz, Eric Miao,
	Ben Dooks, Simtec Linux Team, Todd Fischer, Arnaud Patard,
	Sascha Hauer, Henrik Rydberg, linux-input, linux-kernel

On Fri, Aug 06, 2010 at 02:15:44AM +0530, Trilok Soni wrote:
> > +
> > +/* ************************************************************************
> > + * The cyttsp_xy_worker function reads the XY coordinates and sends them to
> > + * the input layer.  It is scheduled from the interrupt (or timer).
> > + * *************************************************************************/
> > +void handle_single_touch(struct cyttsp_xydata *xy, struct cyttsp_track_data *t,
> > +			 struct cyttsp *ts)
> > +{
> 
> functions should be "static". I would leave a decision to Dmitry if he wants the driver
> to support old single touch protocol hacked up with HAT_xx bits so that driver can support
> two touches with the old single touch protocol itself. 

The ABS_HAT* bits should go away. They were gross abuse even when we did
not have MT protocol and shoudl not be used at all now that we do have
it. I will be cleaning up older drivers (like Elantech) to get rid of
them.

Multitouch devices shouls support either A or B MT protocol. SInce this
device seems to be supporting tracking in hardware it shoudl simply
adhere to protocol B to limit kernel->userspace traffict and be done
with it.

...

> > +
> > +/* schedulable worker entry for timer polling method */
> > +void cyttsp_xy_worker_(struct work_struct *work)
> > +{
> > +	struct cyttsp *ts = container_of(work, struct cyttsp, work);
> > +	cyttsp_xy_worker(ts);
> > +}
> 
> I would really prefer that you remove the polling method from this code as it will simplify
> a code lot. We can delete the whole workqueue because as you will be using request_threaded_irq(...),
> you will not need any workqueue.
> 
 
Seconded. Polling is hardly useful on real production setup as it will
drain battery in no time.

> > +
> > +static int cyttsp_i2c_init(void)
> > +{
> 
> Please add __init like
> 
> static int __init cyttsp_i2c_init(void)
> 
> > +	int retval;
> > +	retval = i2c_add_driver(&cyttsp_i2c_driver);
> > +	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product I2C "
> > +		"Touchscreen Driver (Built %s @ %s) returned %d\n",
> > +		 __func__, __DATE__, __TIME__, retval);
> > +

And lose printk as well. The boot is exremely noisy as it is...

	return i2c_add_driver(&cyttsp_i2c_driver);

is all that is needed.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-05 18:12 ` [PATCH] i2c: cyttsp i2c and spi " Kevin McNeely
  2010-08-05 20:45   ` Trilok Soni
@ 2010-08-05 23:06   ` Henrik Rydberg
  2010-08-07  0:32     ` Kevin McNeely
  2010-08-06  9:06   ` Trilok Soni
  2 siblings, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2010-08-05 23:06 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Ben Dooks, Simtec Linux Team, Todd Fischer,
	Arnaud Patard, Sascha Hauer, linux-input, linux-kernel

On 08/05/2010 08:12 PM, Kevin McNeely wrote:

> From: Fred <fwk@ubuntu.linuxcertified.com>
> 
> This is a new touchscreen driver for the Cypress Semiconductor
> cyttsp family of devices.  This updated driver is for both the i2c and spi
> versions of the devices. The driver code consists of common core code for
> both i2c and spi driver.  This submission is in response to review comments
> from the initial submission.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>
> ---


General impression: There is a lot of useful code in here, but as already
pointed out, well over half of it should not be part of the kernel driver.

Suggestion 1: Clean out the internal state code and use MT protocol B instead.

Suggestion 2: Cut out the single touch calculation, as already pointed out by
Trilok. Why not submit it to the mtdev project instead? The problem is generic
to all new MT drivers, so a common solution while waiting for full MT support in
userspace could be useful.

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-05 18:12 ` [PATCH] i2c: cyttsp i2c and spi " Kevin McNeely
  2010-08-05 20:45   ` Trilok Soni
  2010-08-05 23:06   ` Henrik Rydberg
@ 2010-08-06  9:06   ` Trilok Soni
  2010-08-10  0:49     ` Kevin McNeely
  2 siblings, 1 reply; 70+ messages in thread
From: Trilok Soni @ 2010-08-06  9:06 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Samuel Ortiz, Eric Miao, Ben Dooks,
	Simtec Linux Team, Todd Fischer, Arnaud Patard, Sascha Hauer,
	Henrik Rydberg, linux-input, linux-kernel

Hi Kevin,

Review for SPI code.

> diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
> new file mode 100755


> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/spi/spi.h>
> +#include <linux/delay.h>
> +#include <linux/cyttsp.h>
> +#include "cyttsp_core.h"
> +
> +#define DBG(x)
> +
> +#define CY_SPI_WR_OP      0x00 /* r/~w */
> +#define CY_SPI_RD_OP      0x01
> +#define CY_SPI_CMD_BYTES  4
> +#define CY_SPI_SYNC_BYTES 2
> +#define CY_SPI_SYNC_ACK1  0x62 /* from protocol v.2 */
> +#define CY_SPI_SYNC_ACK2  0x9D /* from protocol v.2 */
> +#define CY_SPI_SYNC_NACK  0x69
> +#define CY_SPI_DATA_SIZE  64
> +#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
> +#define CY_SPI_BITS_PER_WORD 8
> +
> +struct cyttsp_spi {
> +	struct cyttsp_bus_ops ops;
> +	struct spi_device *spi_client;
> +	void *ttsp_client;
> +	u8 wr_buf[CY_SPI_DATA_BUF_SIZE];
> +	u8 rd_buf[CY_SPI_DATA_BUF_SIZE];
> +};
> +
> +static void spi_complete(void *arg)
> +{
> +	complete(arg);

We don't need anything here on completion?

> +}
> +
> +static int spi_sync_tmo(struct spi_device *spi, struct spi_message *message)
> +{
> +	DECLARE_COMPLETION_ONSTACK(done);
> +	int status;
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)

No need.

> +
> +	message->complete = spi_complete;
> +	message->context = &done;
> +	status = spi_async(spi, message);
> +	if (status == 0) {
> +		int ret = wait_for_completion_interruptible_timeout(&done, HZ);
> +		if (!ret) {
> +			printk(KERN_ERR "%s: timeout\n", __func__);
> +			status = -EIO;
> +		} else
> +			status = message->status;
> +	}
> +	message->context = NULL;
> +	return status;
> +}
> +
> +static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts_spi,
> +			    u8 reg, u8 *buf, int length)
> +{
> +	struct spi_message msg;
> +	struct spi_transfer xfer = { 0 };
> +	u8 *wr_buf = ts_spi->wr_buf;
> +	u8 *rd_buf = ts_spi->rd_buf;
> +	int retval;
> +	int i;
> +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)

No need.

> +
> +	if (length > CY_SPI_DATA_SIZE) {
> +		printk(KERN_ERR "%s: length %d is too big.\n",
> +			__func__, length);
> +		return -EINVAL;
> +	}
> +	DBG(printk(KERN_INFO "%s: OP=%s length=%d\n", __func__,
> +		   op == CY_SPI_RD_OP ? "Read" : "Write", length);)

dev_dbg if really needed.

> +
> +	wr_buf[0] = 0x00; /* header byte 0 */
> +	wr_buf[1] = 0xFF; /* header byte 1 */
> +	wr_buf[2] = reg;  /* reg index */
> +	wr_buf[3] = op;   /* r/~w */
> +	if (op == CY_SPI_WR_OP)
> +		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
> +	DBG(
> +	if (op == CY_SPI_RD_OP)
> +		memset(rd_buf, CY_SPI_SYNC_NACK, CY_SPI_DATA_BUF_SIZE);)
> +	DBG(
> +	for (i = 0; i < (length + CY_SPI_CMD_BYTES); i++) {
> +		if ((op == CY_SPI_RD_OP) && (i < CY_SPI_CMD_BYTES))
> +			printk(KERN_INFO "%s: wr[%d]:0x%02x\n",
> +				__func__, i, wr_buf[i]);
> +		if (op == CY_SPI_WR_OP)
> +			printk(KERN_INFO "%s: wr[%d]:0x%02x\n",
> +				__func__, i, wr_buf[i]);
> +	})

Let remove such things.

> +
> +	xfer.tx_buf = wr_buf;
> +	xfer.rx_buf = rd_buf;
> +	xfer.len = length + CY_SPI_CMD_BYTES;
> +
> +	if ((op == CY_SPI_RD_OP) && (xfer.len < 32))
> +		xfer.len += 1;
> +
> +	spi_message_init(&msg);
> +	spi_message_add_tail(&xfer, &msg);
> +	retval = spi_sync_tmo(ts_spi->spi_client, &msg);
> +	if (retval < 0) {
> +		printk(KERN_ERR "%s: spi_sync_tmo() error %d\n",
> +			__func__, retval);
> +		retval = 0;
> +	}
> +	if (op == CY_SPI_RD_OP) {
> +		DBG(
> +		for (i = 0; i < (length + CY_SPI_CMD_BYTES); i++)
> +			printk(KERN_INFO "%s: rd[%d]:0x%02x\n",
> +				__func__, i, rd_buf[i]);)
> +
> +		for (i = 0; i < (length + CY_SPI_CMD_BYTES - 1); i++) {
> +			if ((rd_buf[i] != CY_SPI_SYNC_ACK1) ||
> +				(rd_buf[i + 1] != CY_SPI_SYNC_ACK2)) {
> +				continue;
> +			}
> +			if (i <= (CY_SPI_CMD_BYTES - 1)) {
> +				memcpy(buf, (rd_buf + i + CY_SPI_SYNC_BYTES),
> +					length);
> +				return 0;
> +			}
> +		}
> +		DBG(printk(KERN_INFO "%s: byte sync error\n", __func__);)

dev_err if you really need to print for debugging purpose or pr_err(...)

> +		retval = 1;
> +	}
> +	return retval;
> +}
> +
> +static int cyttsp_spi_xfer(u8 op, struct cyttsp_spi *ts,
> +			    u8 reg, u8 *buf, int length)
> +{
> +	int tries;
> +	int retval;
> +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)

No need.

> +
> +	if (op == CY_SPI_RD_OP) {
> +		for (tries = CY_NUM_RETRY; tries; tries--) {
> +			retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
> +			if (retval == 0)
> +				break;
> +			else
> +				msleep(10);
> +		}
> +	} else {
> +		retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
> +	}
> +	return retval;
> +}
> +
> +static s32 ttsp_spi_read_block_data(void *handle, u8 addr,
> +				    u8 length, void *data)
> +{
> +	int retval;
> +	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
> +
> +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)

No need.

> +
> +	retval = cyttsp_spi_xfer(CY_SPI_RD_OP, ts, addr, data, length);
> +	if (retval < 0)
> +		printk(KERN_ERR "%s: ttsp_spi_read_block_data failed\n",
> +			__func__);

dev_err(...)

> +
> +	/* Do not print the above error if the data sync bytes were not found.
> +	   This is a normal condition for the bootloader loader startup and need
> +	   to retry until data sync bytes are found. */

Use kernel style for multi-line comments.


/* 
 * You should use this format
 * for multi-line commenting
 */



> +	if (retval > 0)
> +		retval = -1;	/* now signal fail; so retry can be done */
> +
> +	return retval;
> +}
> +
> +static s32 ttsp_spi_write_block_data(void *handle, u8 addr,
> +				     u8 length, const void *data)
> +{
> +	int retval;
> +	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
> +
> +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)

No need.

> +
> +	retval = cyttsp_spi_xfer(CY_SPI_WR_OP, ts, addr, (void *)data, length);
> +	if (retval < 0)
> +		printk(KERN_ERR "%s: ttsp_spi_write_block_data failed\n",
> +			__func__);
> +
> +	if (retval == -EIO)
> +		return 0;
> +	else
> +		return retval;
> +}
> +
> +static s32 ttsp_spi_tch_ext(void *handle, void *values)
> +{
> +	int retval = 0;
> +	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
> +
> +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)

No need.

> +
> +	/* Add custom touch extension handling code here */

You may want to add this as "TODO".

> +	/* set: retval < 0 for any returned system errors,
> +		retval = 0 if normal touch handling is required,
> +		retval > 0 if normal touch handling is *not* required */
> +	if (!ts || !values)
> +		retval = -EIO;
> +
> +	return retval;
> +}
> +
> +static int __devinit cyttsp_spi_probe(struct spi_device *spi)
> +{
> +	struct cyttsp_spi *ts_spi;
> +	int retval;
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)

Un-necessary printk.

> +
> +	/* Set up SPI*/
> +	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
> +	spi->mode = SPI_MODE_0;
> +	retval = spi_setup(spi);
> +	if (retval < 0) {
> +		printk(KERN_ERR "%s: SPI setup error %d\n", __func__, retval);

dev_err(...)

> +		return retval;
> +	}
> +	ts_spi = kzalloc(sizeof(*ts_spi), GFP_KERNEL);
> +	if (ts_spi == NULL) {
> +		printk(KERN_ERR "%s: Error, kzalloc\n", __func__);

dev_err(...)

> +		retval = -ENOMEM;
> +		goto error_alloc_data_failed;
> +	}
> +	ts_spi->spi_client = spi;
> +	dev_set_drvdata(&spi->dev, ts_spi);
> +	ts_spi->ops.write = ttsp_spi_write_block_data;
> +	ts_spi->ops.read = ttsp_spi_read_block_data;
> +	ts_spi->ops.ext = ttsp_spi_tch_ext;
> +
> +	ts_spi->ttsp_client = cyttsp_core_init(&ts_spi->ops, &spi->dev);
> +	if (!ts_spi->ttsp_client)
> +		goto ttsp_core_err;
> +	printk(KERN_INFO "%s: Successful registration %s\n",
> +	       __func__, CY_SPI_NAME);


> +
> +	return 0;
> +
> +ttsp_core_err:
> +	kfree(ts_spi);
> +error_alloc_data_failed:
> +	return retval;
> +}
> +
> +/* registered in driver struct */

No need.

> +static int __devexit cyttsp_spi_remove(struct spi_device *spi)
> +{
> +	struct cyttsp_spi *ts_spi = dev_get_drvdata(&spi->dev);
> +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)

Remove this printk.

> +	cyttsp_core_release(ts_spi->ttsp_client);
> +	kfree(ts_spi);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int cyttsp_spi_suspend(struct spi_device *spi, pm_message_t message)
> +{
> +	return cyttsp_suspend(dev_get_drvdata(&spi->dev));
> +}
> +
> +static int cyttsp_spi_resume(struct spi_device *spi)
> +{
> +	return cyttsp_resume(dev_get_drvdata(&spi->dev));
> +}
> +#endif
> +
> +static struct spi_driver cyttsp_spi_driver = {
> +	.driver = {
> +		.name = CY_SPI_NAME,
> +		.bus = &spi_bus_type,
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = cyttsp_spi_probe,
> +	.remove = __devexit_p(cyttsp_spi_remove),
> +#ifdef CONFIG_PM
> +	.suspend = cyttsp_spi_suspend,
> +	.resume = cyttsp_spi_resume,
> +#endif
> +};
> +
> +static int __init cyttsp_spi_init(void)
> +{
> +	int err;
> +
> +	err = spi_register_driver(&cyttsp_spi_driver);
> +	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product SPI "
> +		"Touchscreen Driver (Built %s @ %s) returned %d\n",
> +		 __func__, __DATE__, __TIME__, err);

As Dmitry mentioned on another e-mail, remove such printks. They create un-necessary noise.

> +
> +	return err;
> +}
> +module_init(cyttsp_spi_init);
> +
> +static void __exit cyttsp_spi_exit(void)
> +{
> +	spi_unregister_driver(&cyttsp_spi_driver);
> +	printk(KERN_INFO "%s: module exit\n", __func__);

Ditto.

> +}
> +module_exit(cyttsp_spi_exit);
> +
> +MODULE_ALIAS("spi:cyttsp");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
> +MODULE_AUTHOR("Cypress");
> +
> diff --git a/include/linux/cyttsp.h b/include/linux/cyttsp.h
> new file mode 100755
> index 0000000..b2a289b
> --- /dev/null
> +++ b/include/linux/cyttsp.h

You may want to move this to include/linux/input/cyttsp.h

---Trilok Soni

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-05 23:06   ` Henrik Rydberg
@ 2010-08-07  0:32     ` Kevin McNeely
  2010-08-07  0:49       ` Henrik Rydberg
  0 siblings, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2010-08-07  0:32 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Ben Dooks, Simtec Linux Team, Todd Fischer,
	Arnaud Patard, Sascha Hauer, linux-input, linux-kernel

Hello Henrick,

> -----Original Message-----
> From: Henrik Rydberg [mailto:rydberg@euromail.se]
> Sent: Thursday, August 05, 2010 4:07 PM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Fred; Samuel Ortiz;
Eric
> Miao; Ben Dooks; Simtec Linux Team; Todd Fischer; Arnaud Patard;
Sascha
> Hauer; linux-input@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init
> submit
> 
> On 08/05/2010 08:12 PM, Kevin McNeely wrote:
> 
> > From: Fred <fwk@ubuntu.linuxcertified.com>
> >
> > This is a new touchscreen driver for the Cypress Semiconductor
> > cyttsp family of devices.  This updated driver is for both the i2c
> and spi
> > versions of the devices. The driver code consists of common core
code
> for
> > both i2c and spi driver.  This submission is in response to review
> comments
> > from the initial submission.
> >
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > ---
> 
> 
> General impression: There is a lot of useful code in here, but as
> already
> pointed out, well over half of it should not be part of the kernel
> driver.
> 
> Suggestion 1: Clean out the internal state code and use MT protocol B
> instead.
> 
> Suggestion 2: Cut out the single touch calculation, as already pointed
> out by
> Trilok. Why not submit it to the mtdev project instead? The problem is
> generic
> to all new MT drivers, so a common solution while waiting for full MT
> support in
> userspace could be useful.

I will remove the ST code and polling completely.

However, I would like to keep the MT Protocol A.  Our solution allows
The platform builder to select to use MT protocol B or not as part of 
platform_data in the board configuration. If it makes more sense,
I can reverse the code to default to protocol B and allow the platform
builder developer to select protocol A.

Thank you for the invitation to submit to the mtdev project.
I defer to Dmitry if I should make the next update into the mtdev
project.

Thank you for your review.
-kev

> 
> Thanks,
> Henrik

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-05 21:07     ` Dmitry Torokhov
@ 2010-08-07  0:39       ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-07  0:39 UTC (permalink / raw)
  To: Dmitry Torokhov, Trilok Soni
  Cc: David Brown, Fred, Samuel Ortiz, Eric Miao, Ben Dooks,
	Simtec Linux Team, Todd Fischer, Arnaud Patard, Sascha Hauer,
	Henrik Rydberg, linux-input, linux-kernel

Hello Dmitry,

> -----Original Message-----
> From: Dmitry Torokhov [mailto:dmitry.torokhov@gmail.com]
> Sent: Thursday, August 05, 2010 2:07 PM
> To: Trilok Soni
> Cc: Kevin McNeely; David Brown; Fred; Samuel Ortiz; Eric Miao; Ben
> Dooks; Simtec Linux Team; Todd Fischer; Arnaud Patard; Sascha Hauer;
> Henrik Rydberg; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init
> submit
> 
> On Fri, Aug 06, 2010 at 02:15:44AM +0530, Trilok Soni wrote:
> > > +
> > > +/*
>
***********************************************************************
> *
> > > + * The cyttsp_xy_worker function reads the XY coordinates and
> sends them to
> > > + * the input layer.  It is scheduled from the interrupt (or
> timer).
> > > + *
>
***********************************************************************
> **/
> > > +void handle_single_touch(struct cyttsp_xydata *xy, struct
> cyttsp_track_data *t,
> > > +			 struct cyttsp *ts)
> > > +{
> >
> > functions should be "static". I would leave a decision to Dmitry if
> he wants the driver
> > to support old single touch protocol hacked up with HAT_xx bits so
> that driver can support
> > two touches with the old single touch protocol itself.
> 
> The ABS_HAT* bits should go away. They were gross abuse even when we
> did
> not have MT protocol and shoudl not be used at all now that we do have
> it. I will be cleaning up older drivers (like Elantech) to get rid of
> them.

I will remove the ST code completely.

> 
> Multitouch devices shouls support either A or B MT protocol. SInce
this
> device seems to be supporting tracking in hardware it shoudl simply
> adhere to protocol B to limit kernel->userspace traffict and be done
> with it.
> 
> ...

I have responded to Henrik's review about protocol A and B.
I would like to keep protocol A for now and just change the default
to Protocol B?

> 
> > > +
> > > +/* schedulable worker entry for timer polling method */
> > > +void cyttsp_xy_worker_(struct work_struct *work)
> > > +{
> > > +	struct cyttsp *ts = container_of(work, struct cyttsp, work);
> > > +	cyttsp_xy_worker(ts);
> > > +}
> >
> > I would really prefer that you remove the polling method from this
> code as it will simplify
> > a code lot. We can delete the whole workqueue because as you will be
> using request_threaded_irq(...),
> > you will not need any workqueue.
> >
> 
> Seconded. Polling is hardly useful on real production setup as it will
> drain battery in no time.
> 

I will remove polling completely.

> > > +
> > > +static int cyttsp_i2c_init(void)
> > > +{
> >
> > Please add __init like
> >
> > static int __init cyttsp_i2c_init(void)
> >
> > > +	int retval;
> > > +	retval = i2c_add_driver(&cyttsp_i2c_driver);
> > > +	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product I2C
"
> > > +		"Touchscreen Driver (Built %s @ %s) returned %d\n",
> > > +		 __func__, __DATE__, __TIME__, retval);
> > > +
> 
> And lose printk as well. The boot is exremely noisy as it is...
> 
> 	return i2c_add_driver(&cyttsp_i2c_driver);
> 
> is all that is needed.

I will make this change.

Thank you for your review.
-kev

> 
> --
> Dmitry

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-07  0:32     ` Kevin McNeely
@ 2010-08-07  0:49       ` Henrik Rydberg
  2010-08-10  0:51         ` Kevin McNeely
  0 siblings, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2010-08-07  0:49 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Ben Dooks, Simtec Linux Team, Todd Fischer,
	Arnaud Patard, Sascha Hauer, linux-input, linux-kernel

On 08/07/2010 02:32 AM, Kevin McNeely wrote:

[...]

> However, I would like to keep the MT Protocol A.  Our solution allows

> The platform builder to select to use MT protocol B or not as part of 
> platform_data in the board configuration. If it makes more sense,
> I can reverse the code to default to protocol B and allow the platform
> builder developer to select protocol A.


There is nothing preventing you from keeping say a dkms package somewhere with
all options intact. However, for the kernel, it is a question of
maintainability. If the driver can produce prefectly valid data using protocol
B, and by doing so several hundred lines of code can be removed, that is very
much preferred. Since both protocols can be translated to protocol B via mtdev,
which is already very much in use, there is little reason to support protocol A
when the device can do tracking.

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-05 20:45   ` Trilok Soni
  2010-08-05 21:07     ` Dmitry Torokhov
@ 2010-08-07  0:52     ` Kevin McNeely
  1 sibling, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-07  0:52 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Dmitry Torokhov, David Brown, Fred, Samuel Ortiz, Eric Miao,
	Ben Dooks, Simtec Linux Team, Todd Fischer, Arnaud Patard,
	Sascha Hauer, Henrik Rydberg, linux-input, linux-kernel

HI Trilok,

Thank you for your review.  I am collecting your comments below and
starting
a new revision to incorporate your requests.

> -----Original Message-----
> From: Trilok Soni [mailto:tsoni@codeaurora.org]
> Sent: Thursday, August 05, 2010 1:46 PM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Fred; Samuel Ortiz; Eric Miao; Ben
> Dooks; Simtec Linux Team; Todd Fischer; Arnaud Patard; Sascha Hauer;
> Henrik Rydberg; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init
> submit
> 
> Hi Kevin,
> 
> On 8/5/2010 11:42 PM, Kevin McNeely wrote:
> > From: Fred <fwk@ubuntu.linuxcertified.com>
> >
> 
> E-mail address is is wrong again it seems. Please fix.

Will do.

> 
> You may want to divide this whole patch into three patches:
> 
> 1. core driver
> 2. i2c driver
> 3. spi driver
> 
> > This is a new touchscreen driver for the Cypress Semiconductor
> > cyttsp family of devices.  This updated driver is for both the i2c
> and spi
> > versions of the devices. The driver code consists of common core
code
> for
> > both i2c and spi driver.  This submission is in response to review
> comments
> > from the initial submission.
> >
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > ---
> >  drivers/input/touchscreen/Kconfig            |   33 +
> >  drivers/input/touchscreen/Makefile           |    3 +
> >  drivers/input/touchscreen/cyttsp_board-xxx.c |  110 ++
> >  drivers/input/touchscreen/cyttsp_core.c      | 1778
> ++++++++++++++++++++++++++
> >  drivers/input/touchscreen/cyttsp_core.h      |   49 +
> >  drivers/input/touchscreen/cyttsp_i2c.c       |  183 +++
> >  drivers/input/touchscreen/cyttsp_spi.c       |  339 +++++
> >  include/linux/cyttsp.h                       |  104 ++
> >  8 files changed, 2599 insertions(+), 0 deletions(-)
> >  create mode 100644 drivers/input/touchscreen/cyttsp_board-xxx.c
> >  create mode 100755 drivers/input/touchscreen/cyttsp_core.c
> >  create mode 100755 drivers/input/touchscreen/cyttsp_core.h
> >  create mode 100755 drivers/input/touchscreen/cyttsp_i2c.c
> >  create mode 100755 drivers/input/touchscreen/cyttsp_spi.c
> >  create mode 100755 include/linux/cyttsp.h
> 
> File modes are wrong.
> 

Will fix.

> 
> >
> > diff --git a/drivers/input/touchscreen/Kconfig
> b/drivers/input/touchscreen/Kconfig
> > index 3b9d5e2..b923379 100644
> > --- a/drivers/input/touchscreen/Kconfig
> > +++ b/drivers/input/touchscreen/Kconfig
> > @@ -603,4 +603,37 @@ config TOUCHSCREEN_TPS6507X
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called tps6507x_ts.
> >
> > +config TOUCHSCREEN_CYTTSP_I2C
> > +	default n
> 
> default n is not required.

Will remove.

> 
> > +	tristate "Cypress TTSP i2c touchscreen"
> > +	depends on I2C
> > +	help
> > +	  Say Y here if you have a Cypress TTSP touchscreen
> > +	  connected to your system's i2c bus.
> > +
> > +	  If unsure, say N.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called cyttsp_i2c.
> > +
> > +config TOUCHSCREEN_CYTTSP_SPI
> > +	default n
> 
> Ditto.
> 

Will remove.

> > +	tristate "Cypress TTSP spi touchscreen"
> > +	depends on SPI_MASTER
> > +	help
> > +	  Say Y here if you have a Cypress TTSP touchscreen
> > +	  connected to your system's spi bus.
> > +
> > +	  If unsure, say N.
> > +
> > +	  To compile this driver as a module, choose M here: the
> > +	  module will be called cyttsp_spi.
> > +
> > +config TOUCHSCREEN_CYTTSP_CORE
> > +	default y
> 
> We don't want anything to be default y unless it is curing a cancer.
> 

Will remove.

> > diff --git a/drivers/input/touchscreen/cyttsp_board-xxx.c
> b/drivers/input/touchscreen/cyttsp_board-xxx.c
> 
> This file is good as example only but not for check in. This is a
board
> specific code and the board-xxx.c
> code in appropriate arch will carry this code. Please remove this file
> from the patch.
> 
> > diff --git a/drivers/input/touchscreen/cyttsp_core.c
> b/drivers/input/touchscreen/cyttsp_core.c
> > new file mode 100755
> > index 0000000..95019e9
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp_core.c
> > @@ -0,0 +1,1778 @@
> > +/* Core Source for:
> > + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen
> drivers.
> > + * For use with Cypress Txx2xx and Txx3xx parts.
> > + * Supported parts include:
> > + * CY8CTST241
> > + * CY8CTMG240
> > + * CY8CTST341
> > + * CY8CTMA340
> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> along
> > + * with this program; if not, write to the Free Software
Foundation,
> Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> (kev@cypress.com)
> > + *
> > + */
> > +
> > +#include <linux/delay.h>
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/input.h>
> > +#include <linux/slab.h>
> > +#include <linux/gpio.h>
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/timer.h>
> > +#include <linux/workqueue.h>
> > +#include <linux/byteorder/generic.h>
> > +#include <linux/bitops.h>
> > +#include <linux/cyttsp.h>
> > +#include <linux/ctype.h>
> > +#include "cyttsp_core.h"
> > +
> > +#define DBG(x)
> > +
> > +/* rely on kernel input.h to define Multi-Touch capability */
> > +#ifndef ABS_MT_TRACKING_ID
> > +/* define only if not defined already by system; */
> > +/* value based on linux kernel 2.6.30.10 */
> > +#define ABS_MT_TRACKING_ID (ABS_MT_BLOB_ID + 1)
> > +#endif /* ABS_MT_TRACKING_ID */
> 
> We always support and base our code from latest kernel only. Please
> remove the code
> which relies on supporting older kernels.
> 

Will do.

> > +
> > +#define	TOUCHSCREEN_TIMEOUT (msecs_to_jiffies(28))
> > +/* Bootloader File 0 offset */
> > +#define CY_BL_FILE0       0x00
> > +/* Bootloader command directive */
> > +#define CY_BL_CMD         0xFF
> > +/* Bootloader Enter Loader mode */
> > +#define CY_BL_ENTER       0x38
> > +/* Bootloader Write a Block */
> > +#define CY_BL_WRITE_BLK   0x39
> > +/* Bootloader Terminate Loader mode */
> > +#define CY_BL_TERMINATE   0x3B
> > +/* Bootloader Exit and Verify Checksum command */
> > +#define CY_BL_EXIT        0xA5
> > +/* Bootloader default keys */
> > +#define CY_BL_KEY0 0
> > +#define CY_BL_KEY1 1
> > +#define CY_BL_KEY2 2
> > +#define CY_BL_KEY3 3
> > +#define CY_BL_KEY4 4
> > +#define CY_BL_KEY5 5
> > +#define CY_BL_KEY6 6
> > +#define CY_BL_KEY7 7
> > +
> > +#define CY_DIFF(m, n)               ((m) != (n))
> 
> And why such macro is required? Why can't we just do "if (i != j)"?

Will replace.

> 
> > +
> > +/* TTSP Bootloader Register Map interface definition */
> > +#define CY_BL_CHKSUM_OK 0x01
> > +struct cyttsp_bootloader_data {
> > +	u8 bl_file;
> > +	u8 bl_status;
> > +	u8 bl_error;
> > +	u8 blver_hi;
> > +	u8 blver_lo;
> > +	u8 bld_blver_hi;
> > +	u8 bld_blver_lo;
> > +	u8 ttspver_hi;
> > +	u8 ttspver_lo;
> > +	u8 appid_hi;
> > +	u8 appid_lo;
> > +	u8 appver_hi;
> > +	u8 appver_lo;
> > +	u8 cid_0;
> > +	u8 cid_1;
> > +	u8 cid_2;
> > +};
> > +
> > +#define cyttsp_wake_data cyttsp_xydata
> 
> Why we need to such assignments and introduce these kind of macros? I
> don't think it is necessary.

Will remove.

> 
> > +
> > +struct cyttsp {
> > +	struct device *pdev;
> 
> Most of the time kernel people understands "pdev == platform device
and
> not just device", so better rename this variable
> to "dev" only.
> 
> > +	int irq;
> > +	struct input_dev *input;
> > +	struct work_struct work;
> > +	struct timer_list timer;
> > +	struct mutex mutex;
> > +	char phys[32];
> > +	struct cyttsp_platform_data *platform_data;
> > +	struct cyttsp_bootloader_data bl_data;
> > +	struct cyttsp_sysinfo_data sysinfo_data;
> > +	u8 num_prv_st_tch;
> > +	u16 act_trk[CY_NUM_TRK_ID];
> > +	u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
> > +	u16 prv_st_tch[CY_NUM_ST_TCH_ID];
> > +	u16 prv_mt_pos[CY_NUM_TRK_ID][2];
> > +	struct cyttsp_bus_ops *bus_ops;
> > +	unsigned fw_loader_mode:1;
> > +	unsigned suspended:1;
> > +};
> > +
> > +struct cyttsp_track_data {
> > +	u8 prv_tch;
> > +	u8 cur_tch;
> > +	u16 tmp_trk[CY_NUM_MT_TCH_ID];
> > +	u16 snd_trk[CY_NUM_MT_TCH_ID];
> > +	u16 cur_trk[CY_NUM_TRK_ID];
> > +	u16 cur_st_tch[CY_NUM_ST_TCH_ID];
> > +	u16 cur_mt_tch[CY_NUM_MT_TCH_ID];
> > +	/* if NOT CY_USE_TRACKING_ID then only */
> > +	/* uses CY_NUM_MT_TCH_ID positions */
> > +	u16 cur_mt_pos[CY_NUM_TRK_ID][2];
> > +	/* if NOT CY_USE_TRACKING_ID then only */
> > +	/* uses CY_NUM_MT_TCH_ID positions */
> > +	u8 cur_mt_z[CY_NUM_TRK_ID];
> > +	u8 tool_width;
> > +	u16 st_x1;
> > +	u16 st_y1;
> > +	u8 st_z1;
> > +	u16 st_x2;
> > +	u16 st_y2;
> > +	u8 st_z2;
> > +};
> > +
> > +static const u8 bl_cmd[] = {
> > +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> > +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> > +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> > +	CY_BL_KEY6, CY_BL_KEY7
> > +};
> > +
> > +#define LOCK(m) do { \
> > +	DBG(printk(KERN_INFO "%s: lock\n", __func__);) \
> > +	mutex_lock(&(m)); \
> > +} while (0);
> > +
> > +#define UNLOCK(m) do { \
> > +	DBG(printk(KERN_INFO "%s: unlock\n", __func__);) \
> > +	mutex_unlock(&(m)); \
> > +} while (0);
> 
> Un-necessary debug macros and abstractions. This is not allowed.
Please
> use mutext_lock and unlock
> APIs directly wherever they are required.

Will change.

> 
> > +
> > +DBG(
> > +static void print_data_block(const char *func, u8 command,
> > +			u8 length, void *data)
> > +{
> > +	char buf[1024];
> > +	unsigned buf_len = sizeof(buf);
> > +	char *p = buf;
> > +	int i;
> > +	int l;
> > +
> > +	l = snprintf(p, buf_len, "cmd 0x%x: ", command);
> > +	buf_len -= l;
> > +	p += l;
> > +	for (i = 0; i < length && buf_len; i++, p += l, buf_len -= l)
> > +		l = snprintf(p, buf_len, "%02x ", *((char *)data + i));
> > +	printk(KERN_DEBUG "%s: %s\n", func, buf);
> > +})
> 
> Please don't do like DBG(...) like things. As it is strictly for
> debugging purpose only
> please remove this function from the code itself. Developer in need of
> such debugging routines
> will write down their own when they sit for debugging the problem. I
> don't see any need
> of such debugging helpers in the mainlined version of the driver.

Will remove.

> 
> > +
> > +static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
> > +	u8 length, void *buf)
> > +{
> > +	int rc;
> > +	int tries;
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> > +
> > +	if (!buf || !length) {
> > +		printk(KERN_ERR "%s: Error, buf:%s len:%u\n",
> > +				__func__, !buf ? "NULL" : "OK", length);
> > +		return -EIO;
> > +	}
> > +
> > +	for (tries = 0, rc = 1; tries < CY_NUM_RETRY && rc; tries++)
> > +		rc = ts->bus_ops->read(ts->bus_ops, command, length,
buf);
> > +
> > +	if (rc < 0)
> > +		printk(KERN_ERR "%s: error %d\n", __func__, rc);
> > +	DBG(print_data_block(__func__, command, length, buf);)
> 
> Please use dev_dbg(...) or pr_debug(...) macros directly instead of
> putting
> them under DBG(...).
> 
> It is better you remove DBG(..) from whole driver and replace them
with
> dev_dbg(...) if you have device pointer or use pr_debug(...).

Will do.

> 
> > +
> > +static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
> > +{
> > +	int rc;
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> 
> Un-necessary debug statements. Such statements should be removed from
> the driver.

Will do.

> 
> > +
> > +/*
>
***********************************************************************
> *
> > + * The cyttsp_xy_worker function reads the XY coordinates and sends
> them to
> > + * the input layer.  It is scheduled from the interrupt (or timer).
> > + *
>
***********************************************************************
> **/
> > +void handle_single_touch(struct cyttsp_xydata *xy, struct
> cyttsp_track_data *t,
> > +			 struct cyttsp *ts)
> > +{

Make static. Ok.

> 
> functions should be "static". I would leave a decision to Dmitry if he
> wants the driver
> to support old single touch protocol hacked up with HAT_xx bits so
that
> driver can support
> two touches with the old single touch protocol itself.
> 
> I would prefer not to support this single touch because we are hacking
> up this
> because the userspace frameworks are not converted or supporting the
> new MT based protocols.

ST will be removed completely.

> 
> > +
> > +void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp
> *ts)
> > +{
> 
> static please.

Ok.

> 
> > +
> > +void cyttsp_xy_worker(struct cyttsp *ts)
> > +{
> 
> static please.

Ok.

> 
> > +
> > +	DBG(
> > +	if (trc.cur_tch) {
> > +		unsigned i;
> > +		u8 *pdata = (u8 *)&xy_data;
> > +
> > +		printk(KERN_INFO "%s: TTSP data_pack: ", __func__);
> > +		for (i = 0; i < sizeof(struct cyttsp_xydata); i++)
> > +			printk(KERN_INFO "[%d]=0x%x ", i, pdata[i]);
> > +		printk(KERN_INFO "\n");
> > +	})
> 
> I would really like to remove such DBG formatted code.

Will remove.

> 
> > +
> > +	/* Determine if display is tilted */
> > +	tilt = !!FLIP_DATA(ts->platform_data->flags);
> > +	/* Check for switch in origin */
> > +	rev_x = !!REVERSE_X(ts->platform_data->flags);
> > +	rev_y = !!REVERSE_Y(ts->platform_data->flags);
> > +
> 
> ...
> 
> > +
> > +	/* update platform data for the current multi-touch information
> */
> > +	memcpy(ts->act_trk, trc.cur_trk, CY_NUM_TRK_ID);
> > +
> > +exit_xy_worker:
> > +	DBG(printk(KERN_INFO"%s: finished.\n", __func__);)
> > +	return;
> 
> Do you need this return statment?

Will remove.

> 
> > +}
> > +
> > +/*
>
***********************************************************************
> *
> > + * ISR function. This function is general, initialized in drivers
> init
> > + * function and disables further IRQs until this IRQ is processed
in
> worker.
> > + *
>
***********************************************************************
> **/
> > +static irqreturn_t cyttsp_irq(int irq, void *handle)
> > +{
> > +	struct cyttsp *ts = (struct cyttsp *)handle;
> 
> Casting is not required when the source is void *.
> 
> > +
> > +	DBG(printk(KERN_INFO"%s: Got IRQ!\n", __func__);)
> 
> Un-necessary debug statements.

Will remove.

> 
> > +	cyttsp_xy_worker(ts);
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +/* schedulable worker entry for timer polling method */
> > +void cyttsp_xy_worker_(struct work_struct *work)
> > +{
> > +	struct cyttsp *ts = container_of(work, struct cyttsp, work);
> > +	cyttsp_xy_worker(ts);
> > +}
> 
> I would really prefer that you remove the polling method from this
code
> as it will simplify
> a code lot. We can delete the whole workqueue because as you will be
> using request_threaded_irq(...),
> you will not need any workqueue.
> 

Polling code will be removed completely.

> > +
> > +/* Timer function used as touch interrupt generator for polling
> method */
> > +static void cyttsp_timer(unsigned long handle)
> > +{
> > +	struct cyttsp *ts = (struct cyttsp *)handle;
> > +
> > +	DBG(printk(KERN_INFO"%s: TTSP timer event!\n", __func__);)
> > +	/* schedule motion signal handling */
> > +	if (!work_pending(&ts->work))
> > +		schedule_work(&ts->work);
> > +	mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
> > +	return;
> > +}
> 
> I don't see any need of this timer. Better remove the polling method
> all together to simplify the code.
> Only support interrupt based approach only.
> 

Polling code will be removed completely.

> 
> > +
> > +
> > +/*
>
***********************************************************************
> *
> > + * Probe initialization functions
> > + *
>
***********************************************************************
> * */
> > +static int cyttsp_load_bl_regs(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> > +
> > +	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
> > +				sizeof(ts->bl_data), &(ts->bl_data));
> > +
> > +	if (retval < 0) {
> > +		DBG(printk(KERN_INFO "%s: Failed reading block data,
> err:%d\n",
> > +			__func__, retval);)
> > +		goto fail;
> > +	}
> > +
> > +	DBG({
> > +	      int i;
> > +	      u8 *bl_data = (u8 *)&(ts->bl_data);
> > +	      for (i = 0; i < sizeof(struct cyttsp_bootloader_data);
i++)
> > +			printk(KERN_INFO "%s bl_data[%d]=0x%x\n",
> > +				__func__, i, bl_data[i]);
> > +	})
> 
> Better remove such debug code.

Will remove.

> 
> > +
> > +	return 0;
> > +fail:
> > +	return retval;
> > +}
> 
> ...
> 
> > +
> > +static ssize_t firmware_write(struct kobject *kobj,
> > +				struct bin_attribute *bin_attr,
> > +				char *buf, loff_t pos, size_t size)
> > +{
> > +	struct device *dev = container_of(kobj, struct device, kobj);
> > +	struct cyttsp *ts = dev_get_drvdata(dev);
> > +	LOCK(ts->mutex);
> > +	DBG({
> > +		char str[128];
> > +		char *p = str;
> > +		int i;
> > +		for (i = 0; i < size; i++, p += 2)
> > +			sprintf(p, "%02x", (unsigned char)buf[i]);
> > +		printk(KERN_DEBUG "%s: size %d, pos %ld payload %s\n",
> > +		       __func__, size, (long)pos, str);
> > +	})
> > +	ttsp_write_block_data(ts, CY_REG_BASE, size, buf);
> > +	UNLOCK(ts->mutex);
> > +	return size;
> > +}
> > +
> > +static ssize_t firmware_read(struct kobject *kobj,
> > +	struct bin_attribute *ba,
> > +	char *buf, loff_t pos, size_t size)
> > +{
> > +	int count = 0;
> > +	struct device *dev = container_of(kobj, struct device, kobj);
> > +	struct cyttsp *ts = dev_get_drvdata(dev);
> > +
> > +	LOCK(ts->mutex);
> > +	if (!ts->fw_loader_mode)
> > +		goto exit;
> > +	if (!cyttsp_load_bl_regs(ts)) {
> > +		*(unsigned short *)buf = ts->bl_data.bl_status << 8 |
> > +			ts->bl_data.bl_error;
> > +		count = sizeof(unsigned short);
> > +	} else {
> > +		printk(KERN_ERR "%s: error reading status\n", __func__);
> > +		count = 0;
> > +	}
> > +exit:
> > +	UNLOCK(ts->mutex);
> > +	return count;
> > +}
> 
> This kind of custom interface may not be allowed in the kernel driver.
> Please use
> request_firmware(...) call based interface to support firmware
loading.
> 

Will look into.

> > +
> > +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct
device
> *pdev)
> > +{
> > +	struct input_dev *input_device;
> > +	struct cyttsp *ts;
> > +	int retval = 0;
> > +
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> > +
> > +	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> > +	if (ts == NULL) {
> > +		printk(KERN_ERR "%s: Error, kzalloc\n", __func__);
> > +		goto error_alloc_data_failed;
> > +	}
> > +	mutex_init(&ts->mutex);
> > +	ts->pdev = pdev;
> > +	ts->platform_data = pdev->platform_data;
> > +	ts->bus_ops = bus_ops;
> > +
> > +	if (ts->platform_data->init)
> > +		retval = ts->platform_data->init(1);
> > +	if (retval) {
> > +		printk(KERN_ERR "%s: platform init failed!\n",
__func__);
> > +		goto error_init;
> > +	}
> > +
> > +	if (ts->platform_data->use_timer)
> > +		ts->irq = -1;
> > +	else
> > +		ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
> > +
> > +	retval = cyttsp_power_on(ts);
> > +	if (retval < 0) {
> > +		printk(KERN_ERR "%s: Error, power on failed!\n",
__func__);
> > +		goto error_power_on;
> > +	}
> > +
> > +	/* Create the input device and register it. */
> > +	input_device = input_allocate_device();
> > +	if (!input_device) {
> > +		retval = -ENOMEM;
> > +		printk(KERN_ERR "%s: Error, failed to allocate input
> device\n",
> > +			__func__);
> > +		goto error_input_allocate_device;
> > +	}
> > +
> > +	ts->input = input_device;
> > +	input_device->name = ts->platform_data->name;
> > +	input_device->phys = ts->phys;
> > +	input_device->dev.parent = ts->pdev;
> > +	/* init the touch structures */
> > +	ts->num_prv_st_tch = CY_NTCH;
> > +	memset(ts->act_trk, CY_NTCH, sizeof(ts->act_trk));
> > +	memset(ts->prv_mt_pos, CY_NTCH, sizeof(ts->prv_mt_pos));
> > +	memset(ts->prv_mt_tch, CY_IGNR_TCH, sizeof(ts->prv_mt_tch));
> > +	memset(ts->prv_st_tch, CY_IGNR_TCH, sizeof(ts->prv_st_tch));
> > +
> > +	__set_bit(EV_SYN, input_device->evbit);
> > +	__set_bit(EV_KEY, input_device->evbit);
> > +	__set_bit(EV_ABS, input_device->evbit);
> > +	__set_bit(BTN_TOUCH, input_device->keybit);
> > +	__set_bit(BTN_2, input_device->keybit);
> > +	if (ts->platform_data->use_gestures)
> > +		__set_bit(BTN_3, input_device->keybit);
> > +
> > +	input_set_abs_params(input_device, ABS_X, 0, ts->platform_data-
> >maxx,
> > +			     0, 0);
> > +	input_set_abs_params(input_device, ABS_Y, 0, ts->platform_data-
> >maxy,
> > +			     0, 0);
> > +	input_set_abs_params(input_device, ABS_TOOL_WIDTH, 0,
> > +			     CY_LARGE_TOOL_WIDTH, 0, 0);
> > +	input_set_abs_params(input_device, ABS_PRESSURE, 0, CY_MAXZ, 0,
> 0);
> > +	input_set_abs_params(input_device, ABS_HAT0X, 0,
> > +			     ts->platform_data->maxx, 0, 0);
> > +	input_set_abs_params(input_device, ABS_HAT0Y, 0,
> > +			     ts->platform_data->maxy, 0, 0);
> > +	if (ts->platform_data->use_gestures) {
> > +		input_set_abs_params(input_device, ABS_HAT1X, 0,
CY_MAXZ,
> > +				     0, 0);
> > +		input_set_abs_params(input_device, ABS_HAT1Y, 0,
CY_MAXZ,
> > +				     0, 0);
> > +	}
> > +	if (ts->platform_data->use_mt) {
> > +		input_set_abs_params(input_device, ABS_MT_POSITION_X, 0,
> > +				     ts->platform_data->maxx, 0, 0);
> > +		input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0,
> > +				     ts->platform_data->maxy, 0, 0);
> > +		input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
0,
> > +				     CY_MAXZ, 0, 0);
> > +		input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR,
0,
> > +				     CY_LARGE_TOOL_WIDTH, 0, 0);
> > +		if (ts->platform_data->use_trk_id)
> > +			input_set_abs_params(input_device,
> ABS_MT_TRACKING_ID,
> > +					0, CY_NUM_TRK_ID, 0, 0);
> > +	}
> > +
> > +	if (ts->platform_data->use_virtual_keys)
> > +		input_set_capability(input_device, EV_KEY, KEY_PROG1);
> > +
> > +	retval = input_register_device(input_device);
> > +	if (retval) {
> > +		printk(KERN_ERR "%s: Error, failed to register input
> device\n",
> > +			__func__);
> > +		goto error_input_register_device;
> > +	}
> > +	DBG(printk(KERN_INFO "%s: Registered input device %s\n",
> > +		   __func__, input_device->name);)
> > +
> > +	/* Prepare our worker structure prior to setting up the timer
ISR
> */
> > +	INIT_WORK(&ts->work, cyttsp_xy_worker_);
> > +
> > +	/* Timer or Interrupt setup */
> > +	if (ts->platform_data->use_timer) {
> > +		DBG(printk(KERN_INFO "%s: Setting up Timer\n",
__func__);)
> > +		setup_timer(&ts->timer, cyttsp_timer, (unsigned long)
ts);
> > +		mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
> > +	} else {
> > +		DBG(
> > +		printk(KERN_INFO "%s: Setting up Interrupt. Device
> name=%s\n",
> > +			__func__, input_device->name);)
> > +		retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
> > +				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> > +				   input_device->name, ts);
> > +
> > +		if (retval) {
> > +			printk(KERN_ERR "%s: Error, could not request
irq\n",
> > +				__func__);
> > +			goto error_free_irq;
> > +		} else {
> > +			DBG(printk(KERN_INFO "%s: Interrupt=%d\n",
> > +				__func__, ts->irq);)
> > +		}
> > +	}
> > +	retval = device_create_file(pdev, &fwloader);
> > +	if (retval) {
> > +		printk(KERN_ERR "%s: Error, could not create
attribute\n",
> > +			__func__);
> > +		goto device_create_error;
> > +	}
> > +	dev_set_drvdata(pdev, ts);
> > +	printk(KERN_INFO "%s: Successful.\n", __func__);
> > +	return ts;
> > +
> > +device_create_error:
> > +error_free_irq:
> > +	if (ts->irq >= 0)
> > +		free_irq(ts->irq, ts);
> > +	input_unregister_device(input_device);
> > +error_input_register_device:
> > +	input_free_device(input_device);
> > +error_input_allocate_device:
> > +error_power_on:
> > +	if (ts->platform_data->init)
> > +		ts->platform_data->init(0);
> > +error_init:
> > +	kfree(ts);
> > +error_alloc_data_failed:
> > +	return NULL;
> > +}
> > +
> EXPORT_SYMBOL_GPL(...)?
> 
> > +/* registered in driver struct */
> > +void cyttsp_core_release(void *handle)
> > +{
> > +	struct cyttsp *ts = handle;
> > +
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> > +	cancel_work_sync(&ts->work);
> > +	if (ts->platform_data->use_timer)
> > +		del_timer_sync(&ts->timer);
> > +	else
> > +		free_irq(ts->irq, ts);
> > +	input_unregister_device(ts->input);
> > +	input_free_device(ts->input);
> 
> No need of input_free_device after input_unregister_device.

Will remove.

> 
> > +	if (ts->platform_data->init)
> > +		ts->platform_data->init(0);
> > +	kfree(ts);
> > +}
> 
> EXPORT_SYMBOL_GPL(...)?

Will add.

> 
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen
driver
> core");
> > +MODULE_AUTHOR("Cypress");
> > +
> 
> 
> > diff --git a/drivers/input/touchscreen/cyttsp_i2c.c
> b/drivers/input/touchscreen/cyttsp_i2c.c
> > new file mode 100755
> > index 0000000..ef96105
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp_i2c.c
> > @@ -0,0 +1,183 @@
> > +/* Source for:
> > + * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen
> driver.
> > + * For use with Cypress Txx2xx and Txx3xx parts with I2C interface.
> > + * Supported parts include:
> > + * CY8CTST241
> > + * CY8CTMG240
> > + * CY8CTST341
> > + * CY8CTMA340
> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> along
> > + * with this program; if not, write to the Free Software
Foundation,
> Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> (kev@cypress.com)
> > + *
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/i2c.h>
> > +#include <linux/cyttsp.h>
> > +#include "cyttsp_core.h"
> > +
> > +#define DBG(x)
> > +
> > +struct cyttsp_i2c {
> > +	struct cyttsp_bus_ops ops;
> > +	struct i2c_client *client;
> > +	void *ttsp_client;
> > +};
> > +
> > +static s32 ttsp_i2c_read_block_data(void *handle, u8 addr,
> > +	u8 length, void *values)
> > +{
> > +	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c,
> ops);
> > +	return i2c_smbus_read_i2c_block_data(ts->client,
> > +		addr, length, values);
> > +}
> > +
> > +static s32 ttsp_i2c_write_block_data(void *handle, u8 addr,
> > +	u8 length, const void *values)
> > +{
> > +	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c,
> ops);
> > +	return i2c_smbus_write_i2c_block_data(ts->client,
> > +		addr, length, values);
> > +}
> > +
> > +static s32 ttsp_i2c_tch_ext(void *handle, void *values)
> > +{
> > +	int retval = 0;
> > +	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c,
> ops);
> > +
> > +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
> > +
> > +	/* Add custom touch extension handling code here */
> > +	/* set: retval < 0 for any returned system errors,
> > +		retval = 0 if normal touch handling is required,
> > +		retval > 0 if normal touch handling is *not* required */
> > +	if (!ts || !values)
> > +		retval = -EIO;
> > +
> > +	return retval;
> > +}
> > +static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
> > +	const struct i2c_device_id *id)
> > +{
> > +	struct cyttsp_i2c *ts;
> > +	int retval;
> > +
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> > +
> > +	if (!i2c_check_functionality(client->adapter,
> > +		I2C_FUNC_SMBUS_READ_WORD_DATA))
> > +		return -EIO;
> > +
> > +	/* allocate and clear memory */
> > +	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> > +	if (ts == NULL) {
> > +		printk(KERN_ERR "%s: Error, kzalloc.\n", __func__);
> > +		retval = -ENOMEM;
> > +		goto error_alloc_data_failed;
> > +	}
> > +
> > +	/* register driver_data */
> > +	ts->client = client;
> > +	i2c_set_clientdata(client, ts);
> > +	ts->ops.write = ttsp_i2c_write_block_data;
> > +	ts->ops.read = ttsp_i2c_read_block_data;
> > +	ts->ops.ext = ttsp_i2c_tch_ext;
> > +
> > +	ts->ttsp_client = cyttsp_core_init(&ts->ops, &client->dev);
> > +	if (!ts->ttsp_client)
> > +		goto ttsp_core_err;
> > +
> > +	printk(KERN_INFO "%s: Successful registration %s\n",
> > +		__func__, CY_I2C_NAME);
> > +	return 0;
> > +
> > +ttsp_core_err:
> > +	kfree(ts);
> > +error_alloc_data_failed:
> > +	return retval;
> > +}
> > +
> > +
> > +/* registered in driver struct */
> > +static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
> > +{
> > +	struct cyttsp_i2c *ts;
> > +
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> > +	ts = i2c_get_clientdata(client);
> > +	cyttsp_core_release(ts->ttsp_client);
> > +	kfree(ts);
> > +	return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +static int cyttsp_i2c_suspend(struct i2c_client *client,
> pm_message_t message)
> > +{
> > +	return cyttsp_suspend(dev_get_drvdata(&client->dev));
> > +}
> > +
> > +static int cyttsp_i2c_resume(struct i2c_client *client)
> > +{
> > +	return cyttsp_resume(dev_get_drvdata(&client->dev));
> > +}
> > +#endif
> > +
> > +static const struct i2c_device_id cyttsp_i2c_id[] = {
> > +	{ CY_I2C_NAME, 0 },  { }
> > +};
> > +
> > +static struct i2c_driver cyttsp_i2c_driver = {
> > +	.driver = {
> > +		.name = CY_I2C_NAME,
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe = cyttsp_i2c_probe,
> > +	.remove = __devexit_p(cyttsp_i2c_remove),
> > +	.id_table = cyttsp_i2c_id,
> > +#ifdef CONFIG_PM
> > +	.suspend = cyttsp_i2c_suspend,
> > +	.resume = cyttsp_i2c_resume,
> > +#endif
> > +};
> > +
> > +static int cyttsp_i2c_init(void)
> > +{
> 
> Please add __init like
> 
> static int __init cyttsp_i2c_init(void)

Will add.

> 
> > +	int retval;
> > +	retval = i2c_add_driver(&cyttsp_i2c_driver);
> > +	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product I2C
"
> > +		"Touchscreen Driver (Built %s @ %s) returned %d\n",
> > +		 __func__, __DATE__, __TIME__, retval);
> > +
> > +	return retval;
> > +}
> > +
> > +static void cyttsp_i2c_exit(void)
> 
> __exit
> 

Will add.

> > +{
> > +	return i2c_del_driver(&cyttsp_i2c_driver);
> > +}
> > +
> > +module_init(cyttsp_i2c_init);
> > +module_exit(cyttsp_i2c_exit);
> > +
> > +MODULE_ALIAS("i2c:cyttsp");
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP)
I2C
> driver");
> > +MODULE_AUTHOR("Cypress");
> > +MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
> > diff --git a/drivers/input/touchscreen/cyttsp_spi.c
> b/drivers/input/touchscreen/cyttsp_spi.c
> > new file mode 100755
> > index 0000000..cb6432a
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp_spi.c
> 
> I will comment on spi driver interface later.

Thank you for your review Trilok.
-kev

> 
> ---Trilok Soni
> 
> --
> Sent by a consultant of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
> Forum.

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-06  9:06   ` Trilok Soni
@ 2010-08-10  0:49     ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-10  0:49 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Dmitry Torokhov, David Brown, Samuel Ortiz, Eric Miao, Ben Dooks,
	Simtec Linux Team, Todd Fischer, Arnaud Patard, Sascha Hauer,
	Henrik Rydberg, linux-input, linux-kernel

Hi Trilok,

> -----Original Message-----
> From: Trilok Soni [mailto:tsoni@codeaurora.org]
> Sent: Friday, August 06, 2010 2:07 AM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Samuel Ortiz; Eric Miao; Ben Dooks;
> Simtec Linux Team; Todd Fischer; Arnaud Patard; Sascha Hauer; Henrik
> Rydberg; linux-input@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init
> submit
> 
> Hi Kevin,
> 
> Review for SPI code.
> 
> > diff --git a/drivers/input/touchscreen/cyttsp_spi.c
> b/drivers/input/touchscreen/cyttsp_spi.c
> > new file mode 100755
> 
> 
> > +#include <linux/init.h>
> > +#include <linux/module.h>
> > +#include <linux/spi/spi.h>
> > +#include <linux/delay.h>
> > +#include <linux/cyttsp.h>
> > +#include "cyttsp_core.h"
> > +
> > +#define DBG(x)
> > +
> > +#define CY_SPI_WR_OP      0x00 /* r/~w */
> > +#define CY_SPI_RD_OP      0x01
> > +#define CY_SPI_CMD_BYTES  4
> > +#define CY_SPI_SYNC_BYTES 2
> > +#define CY_SPI_SYNC_ACK1  0x62 /* from protocol v.2 */
> > +#define CY_SPI_SYNC_ACK2  0x9D /* from protocol v.2 */
> > +#define CY_SPI_SYNC_NACK  0x69
> > +#define CY_SPI_DATA_SIZE  64
> > +#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
> > +#define CY_SPI_BITS_PER_WORD 8
> > +
> > +struct cyttsp_spi {
> > +	struct cyttsp_bus_ops ops;
> > +	struct spi_device *spi_client;
> > +	void *ttsp_client;
> > +	u8 wr_buf[CY_SPI_DATA_BUF_SIZE];
> > +	u8 rd_buf[CY_SPI_DATA_BUF_SIZE];
> > +};
> > +
> > +static void spi_complete(void *arg)
> > +{
> > +	complete(arg);
> 
> We don't need anything here on completion?

No, nothing needed.

> 
> > +}
> > +
> > +static int spi_sync_tmo(struct spi_device *spi, struct spi_message
> *message)
> > +{
> > +	DECLARE_COMPLETION_ONSTACK(done);
> > +	int status;
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> 
> No need.

Will remove.

> 
> > +
> > +	message->complete = spi_complete;
> > +	message->context = &done;
> > +	status = spi_async(spi, message);
> > +	if (status == 0) {
> > +		int ret =
wait_for_completion_interruptible_timeout(&done,
> HZ);
> > +		if (!ret) {
> > +			printk(KERN_ERR "%s: timeout\n", __func__);
> > +			status = -EIO;
> > +		} else
> > +			status = message->status;
> > +	}
> > +	message->context = NULL;
> > +	return status;
> > +}
> > +
> > +static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts_spi,
> > +			    u8 reg, u8 *buf, int length)
> > +{
> > +	struct spi_message msg;
> > +	struct spi_transfer xfer = { 0 };
> > +	u8 *wr_buf = ts_spi->wr_buf;
> > +	u8 *rd_buf = ts_spi->rd_buf;
> > +	int retval;
> > +	int i;
> > +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
> 
> No need.

Will remove.

> 
> > +
> > +	if (length > CY_SPI_DATA_SIZE) {
> > +		printk(KERN_ERR "%s: length %d is too big.\n",
> > +			__func__, length);
> > +		return -EINVAL;
> > +	}
> > +	DBG(printk(KERN_INFO "%s: OP=%s length=%d\n", __func__,
> > +		   op == CY_SPI_RD_OP ? "Read" : "Write", length);)
> 
> dev_dbg if really needed.

Will use dev_dbg where needed.

> 
> > +
> > +	wr_buf[0] = 0x00; /* header byte 0 */
> > +	wr_buf[1] = 0xFF; /* header byte 1 */
> > +	wr_buf[2] = reg;  /* reg index */
> > +	wr_buf[3] = op;   /* r/~w */
> > +	if (op == CY_SPI_WR_OP)
> > +		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
> > +	DBG(
> > +	if (op == CY_SPI_RD_OP)
> > +		memset(rd_buf, CY_SPI_SYNC_NACK, CY_SPI_DATA_BUF_SIZE);)
> > +	DBG(
> > +	for (i = 0; i < (length + CY_SPI_CMD_BYTES); i++) {
> > +		if ((op == CY_SPI_RD_OP) && (i < CY_SPI_CMD_BYTES))
> > +			printk(KERN_INFO "%s: wr[%d]:0x%02x\n",
> > +				__func__, i, wr_buf[i]);
> > +		if (op == CY_SPI_WR_OP)
> > +			printk(KERN_INFO "%s: wr[%d]:0x%02x\n",
> > +				__func__, i, wr_buf[i]);
> > +	})
> 
> Let remove such things.

Will do.

> 
> > +
> > +	xfer.tx_buf = wr_buf;
> > +	xfer.rx_buf = rd_buf;
> > +	xfer.len = length + CY_SPI_CMD_BYTES;
> > +
> > +	if ((op == CY_SPI_RD_OP) && (xfer.len < 32))
> > +		xfer.len += 1;
> > +
> > +	spi_message_init(&msg);
> > +	spi_message_add_tail(&xfer, &msg);
> > +	retval = spi_sync_tmo(ts_spi->spi_client, &msg);
> > +	if (retval < 0) {
> > +		printk(KERN_ERR "%s: spi_sync_tmo() error %d\n",
> > +			__func__, retval);
> > +		retval = 0;
> > +	}
> > +	if (op == CY_SPI_RD_OP) {
> > +		DBG(
> > +		for (i = 0; i < (length + CY_SPI_CMD_BYTES); i++)
> > +			printk(KERN_INFO "%s: rd[%d]:0x%02x\n",
> > +				__func__, i, rd_buf[i]);)
> > +
> > +		for (i = 0; i < (length + CY_SPI_CMD_BYTES - 1); i++) {
> > +			if ((rd_buf[i] != CY_SPI_SYNC_ACK1) ||
> > +				(rd_buf[i + 1] != CY_SPI_SYNC_ACK2)) {
> > +				continue;
> > +			}
> > +			if (i <= (CY_SPI_CMD_BYTES - 1)) {
> > +				memcpy(buf, (rd_buf + i +
CY_SPI_SYNC_BYTES),
> > +					length);
> > +				return 0;
> > +			}
> > +		}
> > +		DBG(printk(KERN_INFO "%s: byte sync error\n",
__func__);)
> 
> dev_err if you really need to print for debugging purpose or
> pr_err(...)
> 
> > +		retval = 1;
> > +	}
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_spi_xfer(u8 op, struct cyttsp_spi *ts,
> > +			    u8 reg, u8 *buf, int length)
> > +{
> > +	int tries;
> > +	int retval;
> > +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
> 
> No need.

Will remove.

> 
> > +
> > +	if (op == CY_SPI_RD_OP) {
> > +		for (tries = CY_NUM_RETRY; tries; tries--) {
> > +			retval = cyttsp_spi_xfer_(op, ts, reg, buf,
length);
> > +			if (retval == 0)
> > +				break;
> > +			else
> > +				msleep(10);
> > +		}
> > +	} else {
> > +		retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
> > +	}
> > +	return retval;
> > +}
> > +
> > +static s32 ttsp_spi_read_block_data(void *handle, u8 addr,
> > +				    u8 length, void *data)
> > +{
> > +	int retval;
> > +	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi,
> ops);
> > +
> > +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
> 
> No need.

Will remove.

> 
> > +
> > +	retval = cyttsp_spi_xfer(CY_SPI_RD_OP, ts, addr, data, length);
> > +	if (retval < 0)
> > +		printk(KERN_ERR "%s: ttsp_spi_read_block_data failed\n",
> > +			__func__);
> 
> dev_err(...)
> 
> > +
> > +	/* Do not print the above error if the data sync bytes were not
> found.
> > +	   This is a normal condition for the bootloader loader startup
> and need
> > +	   to retry until data sync bytes are found. */
> 
> Use kernel style for multi-line comments.
> 
> 
> /*
>  * You should use this format
>  * for multi-line commenting
>  */
>

Will do for all.
 
> 
> 
> > +	if (retval > 0)
> > +		retval = -1;	/* now signal fail; so retry can be done
> */
> > +
> > +	return retval;
> > +}
> > +
> > +static s32 ttsp_spi_write_block_data(void *handle, u8 addr,
> > +				     u8 length, const void *data)
> > +{
> > +	int retval;
> > +	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi,
> ops);
> > +
> > +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
> 
> No need.

Will remove.

> 
> > +
> > +	retval = cyttsp_spi_xfer(CY_SPI_WR_OP, ts, addr, (void *)data,
> length);
> > +	if (retval < 0)
> > +		printk(KERN_ERR "%s: ttsp_spi_write_block_data
failed\n",
> > +			__func__);
> > +
> > +	if (retval == -EIO)
> > +		return 0;
> > +	else
> > +		return retval;
> > +}
> > +
> > +static s32 ttsp_spi_tch_ext(void *handle, void *values)
> > +{
> > +	int retval = 0;
> > +	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi,
> ops);
> > +
> > +	DBG(printk(KERN_INFO "%s: Enter\n", __func__);)
> 
> No need.

Will remove.

> 
> > +
> > +	/* Add custom touch extension handling code here */
> 
> You may want to add this as "TODO".
> 
> > +	/* set: retval < 0 for any returned system errors,
> > +		retval = 0 if normal touch handling is required,
> > +		retval > 0 if normal touch handling is *not* required */
> > +	if (!ts || !values)
> > +		retval = -EIO;
> > +
> > +	return retval;
> > +}
> > +
> > +static int __devinit cyttsp_spi_probe(struct spi_device *spi)
> > +{
> > +	struct cyttsp_spi *ts_spi;
> > +	int retval;
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> 
> Un-necessary printk.

Will remove.

> 
> > +
> > +	/* Set up SPI*/
> > +	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
> > +	spi->mode = SPI_MODE_0;
> > +	retval = spi_setup(spi);
> > +	if (retval < 0) {
> > +		printk(KERN_ERR "%s: SPI setup error %d\n", __func__,
> retval);
> 
> dev_err(...)

Will replace all printk with appropriate dev_xxx(...).

> 
> > +		return retval;
> > +	}
> > +	ts_spi = kzalloc(sizeof(*ts_spi), GFP_KERNEL);
> > +	if (ts_spi == NULL) {
> > +		printk(KERN_ERR "%s: Error, kzalloc\n", __func__);
> 
> dev_err(...)

Will replace.

> 
> > +		retval = -ENOMEM;
> > +		goto error_alloc_data_failed;
> > +	}
> > +	ts_spi->spi_client = spi;
> > +	dev_set_drvdata(&spi->dev, ts_spi);
> > +	ts_spi->ops.write = ttsp_spi_write_block_data;
> > +	ts_spi->ops.read = ttsp_spi_read_block_data;
> > +	ts_spi->ops.ext = ttsp_spi_tch_ext;
> > +
> > +	ts_spi->ttsp_client = cyttsp_core_init(&ts_spi->ops, &spi->dev);
> > +	if (!ts_spi->ttsp_client)
> > +		goto ttsp_core_err;
> > +	printk(KERN_INFO "%s: Successful registration %s\n",
> > +	       __func__, CY_SPI_NAME);
> 
> 
> > +
> > +	return 0;
> > +
> > +ttsp_core_err:
> > +	kfree(ts_spi);
> > +error_alloc_data_failed:
> > +	return retval;
> > +}
> > +
> > +/* registered in driver struct */
> 
> No need.

Sorry, this is unclear.

> 
> > +static int __devexit cyttsp_spi_remove(struct spi_device *spi)
> > +{
> > +	struct cyttsp_spi *ts_spi = dev_get_drvdata(&spi->dev);
> > +	DBG(printk(KERN_INFO"%s: Enter\n", __func__);)
> 
> Remove this printk.

Will do.

> 
> > +	cyttsp_core_release(ts_spi->ttsp_client);
> > +	kfree(ts_spi);
> > +	return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +static int cyttsp_spi_suspend(struct spi_device *spi, pm_message_t
> message)
> > +{
> > +	return cyttsp_suspend(dev_get_drvdata(&spi->dev));
> > +}
> > +
> > +static int cyttsp_spi_resume(struct spi_device *spi)
> > +{
> > +	return cyttsp_resume(dev_get_drvdata(&spi->dev));
> > +}
> > +#endif
> > +
> > +static struct spi_driver cyttsp_spi_driver = {
> > +	.driver = {
> > +		.name = CY_SPI_NAME,
> > +		.bus = &spi_bus_type,
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe = cyttsp_spi_probe,
> > +	.remove = __devexit_p(cyttsp_spi_remove),
> > +#ifdef CONFIG_PM
> > +	.suspend = cyttsp_spi_suspend,
> > +	.resume = cyttsp_spi_resume,
> > +#endif
> > +};
> > +
> > +static int __init cyttsp_spi_init(void)
> > +{
> > +	int err;
> > +
> > +	err = spi_register_driver(&cyttsp_spi_driver);
> > +	printk(KERN_INFO "%s: Cypress TrueTouch(R) Standard Product SPI
"
> > +		"Touchscreen Driver (Built %s @ %s) returned %d\n",
> > +		 __func__, __DATE__, __TIME__, err);
> 
> As Dmitry mentioned on another e-mail, remove such printks. They
create
> un-necessary noise.

Will remove.

> 
> > +
> > +	return err;
> > +}
> > +module_init(cyttsp_spi_init);
> > +
> > +static void __exit cyttsp_spi_exit(void)
> > +{
> > +	spi_unregister_driver(&cyttsp_spi_driver);
> > +	printk(KERN_INFO "%s: module exit\n", __func__);
> 
> Ditto.

Will remove.

> 
> > +}
> > +module_exit(cyttsp_spi_exit);
> > +
> > +MODULE_ALIAS("spi:cyttsp");
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP)
SPI
> driver");
> > +MODULE_AUTHOR("Cypress");
> > +
> > diff --git a/include/linux/cyttsp.h b/include/linux/cyttsp.h
> > new file mode 100755
> > index 0000000..b2a289b
> > --- /dev/null
> > +++ b/include/linux/cyttsp.h
> 
> You may want to move this to include/linux/input/cyttsp.h

Will do.


Thank you for your review Trilok.

> 
> ---Trilok Soni
> 
> --
> Sent by a consultant of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora
> Forum.

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init submit
  2010-08-07  0:49       ` Henrik Rydberg
@ 2010-08-10  0:51         ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-08-10  0:51 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Fred, Samuel Ortiz,
	Eric Miao, Ben Dooks, Simtec Linux Team, Todd Fischer,
	Arnaud Patard, Sascha Hauer, linux-input, linux-kernel

Hi Henrik,

> -----Original Message-----
> From: Henrik Rydberg [mailto:rydberg@euromail.se]
> Sent: Friday, August 06, 2010 5:49 PM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Fred; Samuel Ortiz;
Eric
> Miao; Ben Dooks; Simtec Linux Team; Todd Fischer; Arnaud Patard;
Sascha
> Hauer; linux-input@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH] i2c: cyttsp i2c and spi touchscreen driver init
> submit
> 
> On 08/07/2010 02:32 AM, Kevin McNeely wrote:
> 
> [...]
> 
> > However, I would like to keep the MT Protocol A.  Our solution
allows
> 
> > The platform builder to select to use MT protocol B or not as part
of
> > platform_data in the board configuration. If it makes more sense,
> > I can reverse the code to default to protocol B and allow the
> platform
> > builder developer to select protocol A.
> 
> 
> There is nothing preventing you from keeping say a dkms package
> somewhere with
> all options intact. However, for the kernel, it is a question of
> maintainability. If the driver can produce prefectly valid data using
> protocol
> B, and by doing so several hundred lines of code can be removed, that
> is very
> much preferred. Since both protocols can be translated to protocol B
> via mtdev,
> which is already very much in use, there is little reason to support
> protocol A
> when the device can do tracking.

I will remove the Protocol A.

Thank you again for your review.
-kevin

> 
> Thanks,
> Henrik

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
       [not found] <Kevin McNeely <kev@cypress.com>
  2010-07-12 20:56 ` [PATCH] i2c: cyttsp i2c touchscreen driver init submit Kevin McNeely
  2010-08-05 18:12 ` [PATCH] i2c: cyttsp i2c and spi " Kevin McNeely
@ 2010-11-09 18:25 ` Kevin McNeely
  2010-11-15 16:46   ` Henrik Rydberg
  2010-12-02  0:34   ` Dmitry Torokhov
  2010-11-09 18:25 ` [PATCH] i2c: Cypress TTSP G3 MTDEV I2C Device Driver Kevin McNeely
                   ` (10 subsequent siblings)
  13 siblings, 2 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-11-09 18:25 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Henrik Rydberg, Samuel Ortiz, Eric Miao, Simtec Linux Team,
	Luotao Fu, linux-input, linux-kernel

Initial release of Cypress TTSP Gen3 Core Driver.
Core Driver includes platform data definition file,
core driver definition file, and core touchscreen
touch handling of device data. Generates
multi-touch input events.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Kconfig       |    8 +
 drivers/input/touchscreen/Makefile      |    1 +
 drivers/input/touchscreen/cyttsp_core.c |  885 +++++++++++++++++++++++++++++++
 drivers/input/touchscreen/cyttsp_core.h |   55 ++
 include/linux/input/cyttsp.h            |   78 +++
 5 files changed, 1027 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_core.c
 create mode 100644 drivers/input/touchscreen/cyttsp_core.h
 create mode 100644 include/linux/input/cyttsp.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 06ea8da..ee5a31b 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -124,6 +124,14 @@ config TOUCHSCREEN_CY8CTMG110
 	  To compile this driver as a module, choose M here: the
 	  module will be called cy8ctmg110_ts.
 
+config TOUCHSCREEN_CYTTSP_CORE
+	bool "Cypress TTSP touchscreen core"
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system.
+
+	  If unsure, say N.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 7cc1b4f..f629af9 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 0000000..99fd316
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,885 @@
+/* Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Bootloader File 0 offset */
+#define CY_BL_FILE0       0x00
+/* Bootloader command directive */
+#define CY_BL_CMD         0xFF
+/* Bootloader Exit and Verify Checksum command */
+#define CY_BL_EXIT        0xA5
+/* Bootloader number of command keys */
+#define CY_NUM_BL_KEYS    8
+/* Bootloader default command keys */
+#define CY_BL_KEY0 0
+#define CY_BL_KEY1 1
+#define CY_BL_KEY2 2
+#define CY_BL_KEY3 3
+#define CY_BL_KEY4 4
+#define CY_BL_KEY5 5
+#define CY_BL_KEY6 6
+#define CY_BL_KEY7 7
+
+/* helpers */
+#define GET_NUM_TOUCHES(x)          ((x) & 0x0F)
+#define IS_LARGE_AREA(x)            (((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x)               ((x) & 0x20)
+#define IS_VALID_APP(x)             ((x) & 0x01)
+#define IS_OPERATIONAL_ERR(x)       ((x) & 0x3F)
+#define GET_HSTMODE(reg)            ((reg & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)     ((reg & 0x10) >> 4)
+
+/* maximum number of concurrent tracks */
+#define CY_NUM_TCH_ID               4
+/* maximum number of track IDs */
+#define CY_NUM_TRK_ID               16
+
+#define CY_NTCH                     0 /* lift off */
+#define CY_TCH                      1 /* touch down */
+#define CY_SMALL_TOOL_WIDTH         10
+#define CY_LARGE_TOOL_WIDTH         255
+#define CY_REG_BASE                 0x00
+#define CY_REG_GEST_SET             0x1E
+#define CY_REG_ACT_INTRVL           0x1D
+#define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
+#define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
+#define CY_MAXZ                     255
+#define CY_DELAY_SYSINFO            20 /* ms */
+#define CY_HNDSHK_BIT               0x80
+/* device mode bits */
+#define CY_OPERATE_MODE             0x00
+#define CY_SYSINFO_MODE             0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE          0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE          0x02
+#define CY_LOW_POWER_MODE           0x04
+
+/* Touch structure */
+struct cyttsp_touch {
+	u16 x __attribute__ ((packed));
+	u16 y __attribute__ ((packed));
+	u8 z;
+};
+
+/* TrueTouch Standard Product Gen3 interface definition */
+struct cyttsp_xydata {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	struct cyttsp_touch tch1;
+	u8 touch12_id;
+	struct cyttsp_touch tch2;
+	u8 gest_cnt;
+	u8 gest_id;
+	struct cyttsp_touch tch3;
+	u8 touch34_id;
+	struct cyttsp_touch tch4;
+	u8 tt_undef[3];
+	u8 gest_set;
+	u8 tt_reserved;
+};
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[5];
+	u8 scn_typ;
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+struct cyttsp_tch {
+	struct cyttsp_touch *tch;
+	u8 *id;
+};
+
+struct cyttsp_trk {
+	u8 tch;
+	u8 w;
+	u16 x;
+	u16 y;
+	u8 z;
+};
+
+struct cyttsp {
+	struct device *dev;
+	int irq;
+	struct input_dev *input;
+	struct mutex mutex;
+	char phys[32];
+	struct bus_type *bus_type;
+	struct cyttsp_platform_data *platform_data;
+	struct cyttsp_xydata xy_data;
+	struct cyttsp_bootloader_data bl_data;
+	struct cyttsp_sysinfo_data sysinfo_data;
+	struct cyttsp_trk prv_trk[CY_NUM_TRK_ID];
+	struct cyttsp_tch tch_map[CY_NUM_TCH_ID];
+	struct cyttsp_bus_ops *bus_ops;
+	struct timer_list to_timer;
+	bool bl_ready;
+};
+
+struct cyttsp_track_data {
+	struct cyttsp_trk cur_trk[CY_NUM_TRK_ID];
+};
+
+static const u8 bl_command[] = {
+	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
+	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
+	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
+	CY_BL_KEY6, CY_BL_KEY7
+};
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int retval;
+	int tries;
+
+	if (!buf || !length)
+		return -EIO;
+
+	for (tries = 0, retval = -1;
+		tries < CY_NUM_RETRY && (retval < 0);
+		tries++)
+		retval = ts->bus_ops->read(ts->bus_ops, command, length, buf);
+
+	return retval;
+}
+
+static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int retval;
+	if (!buf || !length)
+		return -EIO;
+
+	retval = ts->bus_ops->write(ts->bus_ops, command, length, buf);
+
+	return retval;
+}
+
+static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
+{
+	int retval;
+
+	if (!buf)
+		return -EIO;
+
+	retval = ts->bus_ops->ext(ts->bus_ops, buf);
+
+	return retval;
+}
+
+static irqreturn_t cyttsp_bl_ready_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = handle;
+
+	ts->bl_ready = true;
+	return IRQ_HANDLED;
+}
+
+static int cyttsp_load_bl_regs(struct cyttsp *ts)
+{
+	int retval;
+
+	memset(&(ts->bl_data), 0, sizeof(struct cyttsp_bootloader_data));
+
+	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
+		sizeof(ts->bl_data), &(ts->bl_data));
+
+	return retval;
+}
+
+static int cyttsp_bl_app_valid(struct cyttsp *ts)
+{
+	int retval;
+
+	retval = cyttsp_load_bl_regs(ts);
+
+	if (retval < 0)
+		return -ENODEV;
+
+	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) {
+		if (IS_VALID_APP(ts->bl_data.bl_status)) {
+			dev_dbg(ts->dev, "%s: App found; normal boot\n",
+				__func__);
+			return 0;
+		} else {
+			dev_dbg(ts->dev, "%s: NO APP; load firmware!!\n",
+				__func__);
+			return -ENODEV;
+		}
+	} else if (GET_HSTMODE(ts->bl_data.bl_file) == CY_OPERATE_MODE) {
+		if (!(IS_OPERATIONAL_ERR(ts->bl_data.bl_status))) {
+			dev_dbg(ts->dev, "%s: Operational\n",
+				__func__);
+			return 1;
+		} else {
+			dev_dbg(ts->dev, "%s: Operational failure\n",
+				__func__);
+			return -ENODEV;
+		}
+	} else {
+		dev_dbg(ts->dev, "%s: Non-Operational failure\n",
+			__func__);
+			return -ENODEV;
+	}
+
+}
+
+static bool cyttsp_wait_bl_ready(struct cyttsp *ts, int loop_delay, int max_try)
+{
+	int tries = 0;
+
+	ts->bl_ready = false;	/* wait for interrupt to set ready flag */
+
+	while (!ts->bl_ready && (tries++ < max_try))
+		msleep(loop_delay);
+
+	if (tries < max_try)
+		return true;
+	else
+		return false;
+}
+
+static int cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries = 0;
+	u8 bl_cmd[sizeof(bl_command)];
+
+	memcpy(bl_cmd, bl_command, sizeof(bl_command));
+	if (ts->platform_data->bl_keys)
+		memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
+			ts->platform_data->bl_keys, sizeof(bl_command));
+
+	dev_dbg(ts->dev,
+		"%s: bl_cmd= "
+		"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
+		__func__, bl_cmd[0], bl_cmd[1], bl_cmd[2],
+		bl_cmd[3], bl_cmd[4], bl_cmd[5], bl_cmd[6],
+		bl_cmd[7], bl_cmd[8], bl_cmd[9], bl_cmd[10]);
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE,
+		sizeof(bl_cmd), (void *)bl_cmd);
+	if (retval < 0)
+		return retval;
+
+	do {
+		msleep(500);
+		retval = cyttsp_load_bl_regs(ts);
+	} while (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
+		tries++ < 10 &&
+		!(retval < 0));
+
+	if (retval < 0)
+		return retval;
+	else if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
+		return -ENODEV;
+	else
+		return 0;
+}
+
+static int cyttsp_set_operational_mode(struct cyttsp *ts)
+{
+	int retval;
+	u8 cmd = CY_OPERATE_MODE;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+
+	if (retval < 0)
+		return retval;
+
+	/* wait for TTSP Device to complete switch to Operational mode */
+	msleep(500);
+
+	return retval;
+}
+
+static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+	int retval;
+	u8 cmd = CY_SYSINFO_MODE;
+
+	memset(&(ts->sysinfo_data), 0, sizeof(struct cyttsp_sysinfo_data));
+
+	/* switch to sysinfo mode */
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (retval < 0)
+		return retval;
+
+	msleep(500);
+
+	/* read sysinfo registers */
+	retval = ttsp_read_block_data(ts, CY_REG_BASE,
+		sizeof(ts->sysinfo_data), &(ts->sysinfo_data));
+
+	dev_info(ts->dev, "%s: tv=%02X%02X ai=0x%02X%02X "
+		"av=0x%02X%02X ci=0x%02X%02X%02X\n", "cyttsp",
+		ts->sysinfo_data.tts_verh, ts->sysinfo_data.tts_verl,
+		ts->sysinfo_data.app_idh, ts->sysinfo_data.app_idl,
+		ts->sysinfo_data.app_verh, ts->sysinfo_data.app_verl,
+		ts->sysinfo_data.cid[0], ts->sysinfo_data.cid[1],
+		ts->sysinfo_data.cid[2]);
+
+	return retval;
+}
+
+static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	if ((ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT) ||
+		(ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT) ||
+		(ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT)) {
+
+		u8 intrvl_ray[3];
+
+		intrvl_ray[0] = ts->platform_data->act_intrvl;
+		intrvl_ray[1] = ts->platform_data->tch_tmout;
+		intrvl_ray[2] = ts->platform_data->lp_intrvl;
+
+		/* set intrvl registers */
+		retval = ttsp_write_block_data(ts,
+				CY_REG_ACT_INTRVL,
+				sizeof(intrvl_ray), intrvl_ray);
+
+		msleep(CY_DELAY_SYSINFO);
+	}
+
+	return retval;
+}
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+	int retval;
+	u8 cmd = CY_SOFT_RESET_MODE;
+
+	/* enable bootloader interrupts */
+	retval = request_irq(ts->irq, cyttsp_bl_ready_irq,
+		IRQF_TRIGGER_FALLING, ts->platform_data->name, ts);
+	if (retval)
+		return retval;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (!retval) {
+		if (!cyttsp_wait_bl_ready(ts, 20, 100))
+			retval = -ENODEV;
+		else
+			retval = 0;
+	}
+
+	free_irq(ts->irq, ts);
+	return retval;
+}
+
+static int cyttsp_gesture_setup(struct cyttsp *ts)
+{
+	int retval;
+	u8 gesture_setup;
+
+	/* Init gesture; active distance setup */
+	gesture_setup = ts->platform_data->gest_set;
+	retval = ttsp_write_block_data(ts, CY_REG_GEST_SET,
+		sizeof(gesture_setup), &gesture_setup);
+
+	return retval;
+}
+
+static void cyttsp_init_tch_map(struct cyttsp *ts)
+{
+	ts->tch_map[0].tch = &ts->xy_data.tch1;
+	ts->tch_map[0].id = &ts->xy_data.touch12_id;
+	ts->tch_map[1].tch = &ts->xy_data.tch2;
+	ts->tch_map[1].id = &ts->xy_data.touch12_id;
+	ts->tch_map[2].tch = &ts->xy_data.tch3;
+	ts->tch_map[2].id = &ts->xy_data.touch34_id;
+	ts->tch_map[3].tch = &ts->xy_data.tch4;
+	ts->tch_map[3].id = &ts->xy_data.touch34_id;
+}
+
+static void cyttsp_init_prv_trks(struct cyttsp *ts)
+{
+	/* init the touch structures */
+	memset(ts->prv_trk, CY_NTCH, sizeof(ts->prv_trk));
+}
+
+static void cyttsp_init_cur_trks(struct cyttsp_track_data *t)
+{
+	memset(t->cur_trk, CY_NTCH, sizeof(t->cur_trk));
+}
+
+static int cyttsp_hndshk(struct cyttsp *ts, u8 hst_mode)
+{
+	int retval;
+	u8 cmd;
+
+	cmd = hst_mode & CY_HNDSHK_BIT ?
+		hst_mode & ~CY_HNDSHK_BIT :
+		hst_mode | CY_HNDSHK_BIT;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE,
+		sizeof(cmd), (u8 *)&cmd);
+
+	return retval;
+}
+
+static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
+{
+	u8 id;
+	u8 cnt = 0;
+
+	/* terminate any previous touch where the track
+	 * is missing from the current event
+	 */
+	for (id = 0; id < CY_NUM_TRK_ID; id++) {
+		if (t->cur_trk[id].tch) {
+			/* put active current track data */
+			input_report_abs(ts->input,
+				ABS_MT_TRACKING_ID, id);
+			input_report_abs(ts->input,
+				ABS_MT_WIDTH_MAJOR, t->cur_trk[id].w);
+			input_report_abs(ts->input,
+				ABS_MT_POSITION_X, t->cur_trk[id].x);
+			input_report_abs(ts->input,
+				ABS_MT_POSITION_Y, t->cur_trk[id].y);
+			input_report_abs(ts->input,
+				ABS_MT_TOUCH_MAJOR, t->cur_trk[id].z);
+			input_mt_sync(ts->input);
+
+			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d\n",
+				__func__,
+				t->cur_trk[id].x,
+				t->cur_trk[id].y,
+				t->cur_trk[id].z);
+			/* save current track data into previous track data */
+			ts->prv_trk[id] = t->cur_trk[id];
+			cnt++;
+		} else if (ts->prv_trk[id].tch) {
+			/* put lift-off previous track data */
+			input_report_abs(ts->input,
+				ABS_MT_TRACKING_ID, id);
+			input_report_abs(ts->input,
+				ABS_MT_WIDTH_MAJOR, ts->prv_trk[id].w);
+			input_report_abs(ts->input,
+				ABS_MT_POSITION_X, ts->prv_trk[id].x);
+			input_report_abs(ts->input,
+				ABS_MT_POSITION_Y, ts->prv_trk[id].y);
+			input_report_abs(ts->input,
+				ABS_MT_TOUCH_MAJOR, CY_NTCH);
+			input_mt_sync(ts->input);
+
+			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d lift-off\n",
+				__func__,
+				ts->prv_trk[id].x,
+				ts->prv_trk[id].y,
+				CY_NTCH);
+			ts->prv_trk[id].tch = CY_NTCH;
+			cnt++;
+		}
+	}
+
+	/* signal the view motion event */
+	if (cnt)
+		input_sync(ts->input);
+}
+
+static void cyttsp_get_xydata(struct cyttsp *ts,
+	struct cyttsp_track_data *t,
+	u8 id, u8 w, u16 x, u16 y, u8 z)
+{
+	struct cyttsp_trk *trk;
+
+	trk = &(t->cur_trk[id]);
+	trk->tch = CY_TCH;
+	trk->w = w;
+	trk->x = x;
+	trk->y = y;
+	trk->z = z;
+}
+
+static int cyttsp_xy_worker(struct cyttsp *ts)
+{
+	u8 cur_tch = 0;
+	u8 tch;
+	struct cyttsp_track_data trk;
+
+	/* get event data from CYTTSP device */
+	if (ttsp_read_block_data(ts,
+		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
+		return 0;
+
+	/* touch extension handling */
+	if (ttsp_tch_ext(ts, &ts->xy_data))
+		return 0;
+
+	/* provide flow control handshake */
+	if (ts->platform_data->use_hndshk)
+		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
+			return 0;
+
+	cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
+
+	if (ts->bus_ops->power_state == CY_IDLE_STATE)
+		return 0;
+	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
+		return -1;
+	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
+		/* terminate all active tracks */
+		cur_tch = CY_NTCH;
+		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
+	} else if (cur_tch > CY_NUM_TCH_ID) {
+		/* terminate all active tracks */
+		cur_tch = CY_NTCH;
+		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
+	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
+		/* terminate all active tracks */
+		cur_tch = CY_NTCH;
+		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
+	}
+
+	/* process the touches */
+	cyttsp_init_cur_trks(&trk);
+
+	for (tch = 0; tch < cur_tch; tch++) {
+		cyttsp_get_xydata(ts, &trk,
+			tch & 0x01 ?
+			(*(ts->tch_map[tch].id) & 0x0F) :
+			(*(ts->tch_map[tch].id) & 0xF0) >> 4,
+			CY_SMALL_TOOL_WIDTH,
+			be16_to_cpu((ts->tch_map[tch].tch)->x),
+			be16_to_cpu((ts->tch_map[tch].tch)->y),
+			(ts->tch_map[tch].tch)->z);
+	}
+
+	handle_multi_touch(&trk, ts);
+
+	return 0;
+}
+
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = handle;
+	int retval;
+
+	retval = cyttsp_xy_worker(ts);
+
+	if (retval < 0) {
+		/* TTSP device has reset back to bootloader mode
+		 * Reset driver touch history and restore operational mode
+		 */
+		cyttsp_init_prv_trks(ts);
+		retval = cyttsp_exit_bl_mode(ts);
+		if (retval)
+			ts->bus_ops->power_state = CY_IDLE_STATE;
+		dev_info(ts->dev, "%s: %s\n",
+			__func__,
+			(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
+			"ACTIVE" : "IDLE");
+	}
+	return IRQ_HANDLED;
+}
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	ts->bus_ops->power_state = CY_IDLE_STATE;
+
+	retval = cyttsp_bl_app_valid(ts);
+	if (retval < 0)
+		goto bypass;
+	else if (retval > 0) {
+		retval = cyttsp_soft_reset(ts);
+		if (retval < 0)
+			goto bypass;
+	}
+
+	retval = cyttsp_exit_bl_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_set_sysinfo_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_set_sysinfo_regs(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_set_operational_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	/* enable touch interrupts */
+	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		ts->platform_data->name, ts);
+	if (retval < 0)
+		goto bypass;
+
+	/* init gesture setup; required for active distance */
+	retval = cyttsp_gesture_setup(ts);
+
+bypass:
+	if (!retval)
+		ts->bus_ops->power_state = CY_ACTIVE_STATE;
+
+	dev_info(ts->dev, "%s: %s\n",
+		__func__,
+		(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
+		"ACTIVE" : "IDLE");
+	return retval;
+}
+
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle)
+{
+	struct cyttsp *ts = handle;
+	int retval = 0;
+	struct cyttsp_xydata xydata;
+
+	if (ts->platform_data->use_sleep && (ts->bus_ops->power_state !=
+		CY_ACTIVE_STATE)) {
+		if (ts->platform_data->wakeup) {
+			retval = ts->platform_data->wakeup();
+			if (retval < 0)
+				dev_dbg(ts->dev, "%s: Error, wakeup failed!\n",
+					__func__);
+		} else {
+			dev_dbg(ts->dev, "%s: Error, wakeup not implemented "
+				"(check board file).\n", __func__);
+			retval = -ENOSYS;
+		}
+		if (!(retval < 0)) {
+			retval = ttsp_read_block_data(ts, CY_REG_BASE,
+				sizeof(xydata), &xydata);
+			if (!(retval < 0) && !GET_HSTMODE(xydata.hst_mode))
+				ts->bus_ops->power_state = CY_ACTIVE_STATE;
+		}
+	}
+	dev_dbg(ts->dev, "%s: Wake Up %s\n", __func__,
+		(retval < 0) ? "FAIL" : "PASS");
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cyttsp_resume);
+
+int cyttsp_suspend(void *handle)
+{
+	struct cyttsp *ts = handle;
+	u8 sleep_mode = 0;
+	int retval = 0;
+
+	if (ts->platform_data->use_sleep &&
+		(ts->bus_ops->power_state == CY_ACTIVE_STATE)) {
+		sleep_mode = CY_DEEP_SLEEP_MODE;
+		retval = ttsp_write_block_data(ts,
+			CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
+		if (!(retval < 0))
+			ts->bus_ops->power_state = CY_SLEEP_STATE;
+	}
+	dev_dbg(ts->dev, "%s: Sleep Power state is %s\n", __func__,
+		(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
+		"ACTIVE" :
+		((ts->bus_ops->power_state == CY_SLEEP_STATE) ?
+		"SLEEP" : "LOW POWER"));
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cyttsp_suspend);
+#endif
+
+int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
+	struct device *dev, void *handle)
+{
+	struct input_dev *input_device;
+	struct cyttsp *ts;
+	int retval = 0;
+
+	if ((dev == NULL) || (bus_ops == NULL))
+		goto error_alloc_data;
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (ts == NULL) {
+		dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
+		retval = -ENOMEM;
+		goto error_alloc_data;
+	}
+	mutex_init(&ts->mutex);
+	ts->dev = dev;
+	ts->platform_data = dev->platform_data;
+	ts->bus_ops = bus_ops;
+	ts->platform_data->dev = ts->dev;
+
+	if (ts->platform_data->init) {
+		retval = ts->platform_data->init(ts->platform_data, 1);
+		if (retval) {
+			dev_dbg(ts->dev, "%s: Error, platform init failed!\n",
+				__func__);
+			retval = -EIO;
+			goto error_init;
+		}
+	}
+
+	ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
+	if (ts->irq <= 0) {
+		dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
+			__func__);
+			retval = -EIO;
+			goto error_init;
+	}
+
+	/* Create the input device and register it. */
+	input_device = input_allocate_device();
+	if (!input_device) {
+		retval = -ENOMEM;
+		dev_dbg(ts->dev, "%s: Error, failed to allocate input device\n",
+			__func__);
+			retval = -ENODEV;
+		goto error_input_allocate_device;
+	}
+
+	ts->input = input_device;
+	input_device->name = ts->platform_data->name;
+	input_device->phys = ts->phys;
+	input_device->dev.parent = ts->dev;
+	ts->bus_type = bus_ops->dev->bus;
+
+	cyttsp_init_tch_map(ts);
+	cyttsp_init_prv_trks(ts);
+
+	__set_bit(EV_SYN, input_device->evbit);
+	__set_bit(EV_KEY, input_device->evbit);
+	__set_bit(EV_ABS, input_device->evbit);
+
+	input_set_abs_params(input_device, ABS_MT_POSITION_X,
+		0, ts->platform_data->maxx, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_POSITION_Y,
+		0, ts->platform_data->maxy, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
+		0, CY_MAXZ, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR,
+		0, CY_LARGE_TOOL_WIDTH, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
+		0, CY_NUM_TRK_ID, 0, 0);
+
+	retval = input_register_device(input_device);
+	if (retval) {
+		dev_dbg(ts->dev, "%s: Error, failed to register input device\n",
+			__func__);
+			retval = -ENODEV;
+		goto error_input_register_device;
+	}
+
+	retval = cyttsp_power_on(ts);
+
+	if (retval < 0) {
+		dev_dbg(ts->dev, "%s: Error, power on failed!\n", __func__);
+		retval = -ENODEV;
+		goto error_power_on;
+	}
+
+	handle = ts;
+	goto no_error;
+
+error_power_on:
+	free_irq(ts->irq, ts);
+error_input_register_device:
+	input_unregister_device(input_device);
+error_input_allocate_device:
+	if (ts->platform_data->init)
+		ts->platform_data->init(ts->platform_data, 0);
+error_init:
+	mutex_destroy(&ts->mutex);
+	kfree(ts);
+error_alloc_data:
+	handle = NULL;
+no_error:
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cyttsp_core_init);
+
+/* registered in driver struct */
+void cyttsp_core_release(void *handle)
+{
+	struct cyttsp *ts = handle;
+
+	mutex_destroy(&ts->mutex);
+	free_irq(ts->irq, ts);
+	input_unregister_device(ts->input);
+	if (ts->platform_data->init)
+		ts->platform_data->init(ts->platform_data, 0);
+	kfree(ts);
+}
+EXPORT_SYMBOL_GPL(cyttsp_core_release);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
+MODULE_AUTHOR("Cypress");
+
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
new file mode 100644
index 0000000..43fe438
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -0,0 +1,55 @@
+/* Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+
+#ifndef __CYTTSP_CORE_H__
+#define __CYTTSP_CORE_H__
+
+#include <linux/kernel.h>
+#include <linux/input/cyttsp.h>
+
+#define CY_NUM_RETRY                4 /* max number of retries for read ops */
+
+
+struct cyttsp_bus_ops {
+	s32 (*write)(void *handle, u8 addr, u8 length, const void *values);
+	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
+	s32 (*ext)(void *handle, void *values);
+	struct device *dev;
+	enum cyttsp_powerstate power_state;
+};
+
+int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
+	struct device *dev, void *handle);
+
+void cyttsp_core_release(void *handle);
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle);
+int cyttsp_suspend(void *handle);
+#endif
+
+#endif /* __CYTTSP_CORE_H__ */
diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
new file mode 100644
index 0000000..5280252
--- /dev/null
+++ b/include/linux/input/cyttsp.h
@@ -0,0 +1,78 @@
+/* Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+#ifndef _CYTTSP_H_
+#define _CYTTSP_H_
+
+#define CY_SPI_NAME "cyttsp-spi"
+#define CY_I2C_NAME "cyttsp-i2c"
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT 0x00
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT 0xFF
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT 0x0A
+/*
+ * Active distance in pixels for a gesture to be reported
+ * if set to 0, then all gesture movements are reported
+ * Valid range is 0 - 15
+ */
+#define CY_ACT_DIST_DFLT 8
+#define CY_ACT_DIST CY_ACT_DIST_DFLT
+
+enum cyttsp_gest {
+	CY_GEST_GRP_NONE = 0,
+	CY_GEST_GRP1 =	0x10,
+	CY_GEST_GRP2 = 0x20,
+	CY_GEST_GRP3 = 0x40,
+	CY_GEST_GRP4 = 0x80,
+};
+
+enum cyttsp_powerstate {
+	CY_IDLE_STATE,
+	CY_ACTIVE_STATE,
+	CY_LOW_PWR_STATE,
+	CY_SLEEP_STATE,
+};
+
+struct cyttsp_platform_data {
+	struct device *dev;
+	u32 maxx;
+	u32 maxy;
+	unsigned use_hndshk:1;
+	unsigned use_sleep:1;
+	u8 gest_set;	/* Active distance */
+	u8 act_intrvl;  /* Active refresh interval; ms */
+	u8 tch_tmout;   /* Active touch timeout; ms */
+	u8 lp_intrvl;   /* Low power refresh interval; ms */
+	int (*wakeup)(void);
+	int (*init)(struct cyttsp_platform_data *, int on_off);
+	char *name;
+	s16 irq_gpio;
+	u8 *bl_keys;
+};
+
+#endif /* _CYTTSP_H_ */
-- 
1.7.2.1


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH] i2c: Cypress TTSP G3 MTDEV I2C Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (2 preceding siblings ...)
  2010-11-09 18:25 ` [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
@ 2010-11-09 18:25 ` Kevin McNeely
  2010-11-09 18:25 ` [PATCH] spi: Cypress TTSP G3 MTDEV SPI " Kevin McNeely
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-11-09 18:25 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Simtec Linux Team, Henrik Rydberg,
	Luotao Fu, linux-input, linux-kernel

Initial release of Cypress TTSP Gen3 I2C Device Driver.
Provides i2C communication modules for the Cypress
TTSP Gen3 MTDEV Core Driver.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Kconfig      |   10 ++
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/cyttsp_i2c.c |  185 ++++++++++++++++++++++++++++++++
 3 files changed, 196 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_i2c.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index ee5a31b..bc21ed9 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -132,6 +132,16 @@ config TOUCHSCREEN_CYTTSP_CORE
 
 	  If unsure, say N.
 
+config TOUCHSCREEN_CYTTSP_I2C
+	bool "Cypress TTSP touchscreen I2C driver"
+	depends on I2C
+	depends on TOUCHSCREEN_CYTTSP_CORE
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system with an I2C interface.
+
+	  If unsure, say N.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f629af9..9c142b8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100644
index 0000000..cacfe4d
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -0,0 +1,185 @@
+/* Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#define CY_I2C_DATA_SIZE  128
+
+struct cyttsp_i2c {
+	struct cyttsp_bus_ops ops;
+	struct i2c_client *client;
+	void *ttsp_client;
+	u8 wr_buf[CY_I2C_DATA_SIZE];
+};
+
+static s32 ttsp_i2c_read_block_data(void *handle, u8 addr,
+	u8 length, void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval = 0;
+
+	retval = i2c_master_send(ts->client, &addr, 1);
+	if (retval < 0)
+		return retval;
+
+	retval = i2c_master_recv(ts->client, values, length);
+
+	return (retval < 0) ? retval : 0;
+}
+
+static s32 ttsp_i2c_write_block_data(void *handle, u8 addr,
+	u8 length, const void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval;
+
+	ts->wr_buf[0] = addr;
+	memcpy(&ts->wr_buf[1], values, length);
+
+	retval = i2c_master_send(ts->client, ts->wr_buf, length+1);
+
+	return (retval < 0) ? retval : 0;
+}
+
+static s32 ttsp_i2c_tch_ext(void *handle, void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval = 0;
+
+	/* TODO: Add custom touch extension handling code here
+	 * set: retval < 0 for any returned system errors,
+	 *	retval = 0 if normal touch handling is required,
+	 *	retval > 0 if normal touch handling is *not* required
+	 */
+	if (!ts || !values)
+		retval = -EIO;
+
+	return retval;
+}
+static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct cyttsp_i2c *ts;
+	int retval;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -EIO;
+
+	/* allocate and clear memory */
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (ts == NULL) {
+		dev_dbg(&client->dev, "%s: Error, kzalloc.\n", __func__);
+		retval = -ENOMEM;
+		goto error_alloc_data_failed;
+	}
+
+	/* register driver_data */
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	ts->ops.write = ttsp_i2c_write_block_data;
+	ts->ops.read = ttsp_i2c_read_block_data;
+	ts->ops.ext = ttsp_i2c_tch_ext;
+	ts->ops.dev = &client->dev;
+	ts->ops.dev->bus = &i2c_bus_type;
+
+	retval = cyttsp_core_init(&ts->ops, &client->dev, &ts->ttsp_client);
+	if (retval)
+		goto ttsp_core_err;
+
+	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
+
+	return 0;
+
+ttsp_core_err:
+	kfree(ts);
+error_alloc_data_failed:
+	return retval;
+}
+
+
+/* registered in driver struct */
+static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+{
+	struct cyttsp_i2c *ts;
+
+	ts = i2c_get_clientdata(client);
+	cyttsp_core_release(ts->ttsp_client);
+	kfree(ts);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	return cyttsp_suspend(dev_get_drvdata(&client->dev));
+}
+
+static int cyttsp_i2c_resume(struct i2c_client *client)
+{
+	return cyttsp_resume(dev_get_drvdata(&client->dev));
+}
+#endif
+
+static const struct i2c_device_id cyttsp_i2c_id[] = {
+	{ CY_I2C_NAME, 0 },  { }
+};
+
+static struct i2c_driver cyttsp_i2c_driver = {
+	.driver = {
+		.name = CY_I2C_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_i2c_probe,
+	.remove = __devexit_p(cyttsp_i2c_remove),
+	.id_table = cyttsp_i2c_id,
+#ifdef CONFIG_PM
+	.suspend = cyttsp_i2c_suspend,
+	.resume = cyttsp_i2c_resume,
+#endif
+};
+
+static int __init cyttsp_i2c_init(void)
+{
+	return i2c_add_driver(&cyttsp_i2c_driver);
+}
+
+static void __exit cyttsp_i2c_exit(void)
+{
+	return i2c_del_driver(&cyttsp_i2c_driver);
+}
+
+module_init(cyttsp_i2c_init);
+module_exit(cyttsp_i2c_exit);
+
+MODULE_ALIAS("i2c:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
-- 
1.7.2.1


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [PATCH] spi: Cypress TTSP G3 MTDEV SPI Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (3 preceding siblings ...)
  2010-11-09 18:25 ` [PATCH] i2c: Cypress TTSP G3 MTDEV I2C Device Driver Kevin McNeely
@ 2010-11-09 18:25 ` Kevin McNeely
  2010-12-04  2:06 ` [v2] touchscreen Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-11-09 18:25 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Simtec Linux Team, Henrik Rydberg,
	Luotao Fu, linux-input, linux-kernel

Initial release of Cypress TTSP Gen3 SPI Device Driver.
Provides SPI communication modules for the Cypress
TTSP Gen3 MTDEV Core Driver.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Kconfig      |   10 +
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/cyttsp_spi.c |  303 ++++++++++++++++++++++++++++++++
 3 files changed, 314 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_spi.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index ee5a31b..052d5e2 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -132,6 +132,16 @@ config TOUCHSCREEN_CYTTSP_CORE
 
 	  If unsure, say N.
 
+config TOUCHSCREEN_CYTTSP_SPI
+	bool "Cypress TTSP touchscreen SPI driver"
+	depends on SPI_MASTER
+	depends on TOUCHSCREEN_CYTTSP_CORE
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system with a SPI interface.
+
+	  If unsure, say N.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f629af9..89557f2 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)	+= cyttsp_spi.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100644
index 0000000..9f05de4
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -0,0 +1,303 @@
+/* Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#define CY_SPI_WR_OP      0x00 /* r/~w */
+#define CY_SPI_RD_OP      0x01
+#define CY_SPI_CMD_BYTES  4
+#define CY_SPI_SYNC_BYTES 2
+#define CY_SPI_SYNC_ACK1  0x62 /* from protocol v.2 */
+#define CY_SPI_SYNC_ACK2  0x9D /* from protocol v.2 */
+#define CY_SPI_DATA_SIZE  128
+#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+#define CY_SPI_BITS_PER_WORD 8
+
+struct cyttsp_spi {
+	struct cyttsp_bus_ops ops;
+	struct spi_device *spi_client;
+	void *ttsp_client;
+	u8 wr_buf[CY_SPI_DATA_BUF_SIZE];
+	u8 rd_buf[CY_SPI_DATA_BUF_SIZE];
+};
+
+static void spi_complete(void *arg)
+{
+	complete(arg);
+}
+
+static int spi_sync_tmo(struct cyttsp_spi *ts, struct spi_message *message)
+{
+	DECLARE_COMPLETION_ONSTACK(done);
+	int status;
+
+	message->complete = spi_complete;
+	message->context = &done;
+	status = spi_async(ts->spi_client, message);
+	if (status == 0) {
+		int ret = wait_for_completion_interruptible_timeout(&done, HZ);
+		if (!ret) {
+			dev_dbg(ts->ops.dev, "%s: timeout\n", __func__);
+			status = -EIO;
+		} else
+			status = message->status;
+	}
+	message->context = NULL;
+	return status;
+}
+
+static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts,
+			    u8 reg, u8 *buf, int length)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer = { 0 };
+	u8 *wr_buf = ts->wr_buf;
+	u8 *rd_buf = ts->rd_buf;
+	int retval;
+	int i;
+
+	if (length > CY_SPI_DATA_SIZE) {
+		dev_dbg(ts->ops.dev, "%s: length %d is too big.\n",
+			__func__, length);
+		return -EINVAL;
+	}
+	dev_dbg(ts->ops.dev, "%s: OP=%s length=%d\n", __func__,
+		   op == CY_SPI_RD_OP ? "Read" : "Write", length);
+
+	wr_buf[0] = 0x00; /* header byte 0 */
+	wr_buf[1] = 0xFF; /* header byte 1 */
+	wr_buf[2] = reg;  /* reg index */
+	wr_buf[3] = op;   /* r/~w */
+	if (op == CY_SPI_WR_OP)
+		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+
+	xfer.tx_buf = wr_buf;
+	xfer.rx_buf = rd_buf;
+	xfer.len = length + CY_SPI_CMD_BYTES;
+
+	if ((op == CY_SPI_RD_OP) && (xfer.len < 32))
+		xfer.len += 1;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+	retval = spi_sync_tmo(ts, &msg);
+	if (retval < 0) {
+		dev_dbg(ts->ops.dev, "%s: spi_sync_tmo() error %d\n",
+			__func__, retval);
+		retval = 0;
+	}
+	if (op == CY_SPI_RD_OP) {
+		for (i = 0; i < (length + CY_SPI_CMD_BYTES - 1); i++) {
+			if ((rd_buf[i] != CY_SPI_SYNC_ACK1) ||
+				(rd_buf[i + 1] != CY_SPI_SYNC_ACK2)) {
+				continue;
+			}
+			if (i <= (CY_SPI_CMD_BYTES - 1)) {
+				memcpy(buf, (rd_buf + i + CY_SPI_SYNC_BYTES),
+					length);
+				return 0;
+			}
+		}
+		dev_dbg(ts->ops.dev, "%s: byte sync error\n", __func__);
+		retval = 1;
+	}
+	return retval;
+}
+
+static int cyttsp_spi_xfer(u8 op, struct cyttsp_spi *ts,
+			    u8 reg, u8 *buf, int length)
+{
+	int tries;
+	int retval;
+
+	if (op == CY_SPI_RD_OP) {
+		for (tries = CY_NUM_RETRY; tries; tries--) {
+			retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+			if (retval == 0)
+				break;
+			else
+				msleep(20);
+		}
+	} else {
+		retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+	}
+
+	return retval;
+}
+
+static s32 ttsp_spi_read_block_data(void *handle, u8 addr,
+				    u8 length, void *data)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval;
+
+	retval = cyttsp_spi_xfer(CY_SPI_RD_OP, ts, addr, data, length);
+	if (retval < 0)
+		dev_dbg(ts->ops.dev,  "%s: ttsp_spi_read_block_data failed\n",
+			__func__);
+
+	/* Do not print the above error if the data sync bytes were not found.
+	 * This is a normal condition for the bootloader loader startup and need
+	 * to retry until data sync bytes are found.
+	 */
+	if (retval > 0)
+		retval = -1;	/* now signal fail; so retry can be done */
+
+	return retval;
+}
+
+static s32 ttsp_spi_write_block_data(void *handle, u8 addr,
+				     u8 length, const void *data)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval;
+
+	retval = cyttsp_spi_xfer(CY_SPI_WR_OP, ts, addr, (void *)data, length);
+	if (retval < 0)
+		dev_dbg(ts->ops.dev, "%s: ttsp_spi_write_block_data failed\n",
+			__func__);
+
+	if (retval == -EIO)
+		return 0;
+	else
+		return retval;
+}
+
+static s32 ttsp_spi_tch_ext(void *handle, void *values)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval = 0;
+
+	/* TODO: Add custom touch extension handling code here
+	 * set: retval < 0 for any returned system errors,
+	 *	retval = 0 if normal touch handling is required,
+	 *	retval > 0 if normal touch handling is *not* required
+	 */
+
+	if (!ts || !values)
+		retval = -EIO;
+
+	return retval;
+}
+
+static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts;
+	int retval;
+
+	/* Set up SPI*/
+	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+	spi->mode = SPI_MODE_0;
+	retval = spi_setup(spi);
+	if (retval < 0) {
+		dev_dbg(&spi->dev, "%s: SPI setup error %d\n",
+			__func__, retval);
+		return retval;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (ts == NULL) {
+		dev_dbg(&spi->dev, "%s: Error, kzalloc\n", __func__);
+		retval = -ENOMEM;
+		goto error_alloc_data_failed;
+	}
+	ts->spi_client = spi;
+	dev_set_drvdata(&spi->dev, ts);
+	ts->ops.write = ttsp_spi_write_block_data;
+	ts->ops.read = ttsp_spi_read_block_data;
+	ts->ops.ext = ttsp_spi_tch_ext;
+	ts->ops.dev = &spi->dev;
+
+	retval = cyttsp_core_init(&ts->ops, &spi->dev,  &ts->ttsp_client);
+	if (retval)
+		goto ttsp_core_err;
+
+	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
+
+	return 0;
+
+ttsp_core_err:
+	kfree(ts);
+error_alloc_data_failed:
+	return retval;
+}
+
+static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev);
+
+	cyttsp_core_release(ts->ttsp_client);
+	kfree(ts);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	return cyttsp_suspend(dev_get_drvdata(&spi->dev));
+}
+
+static int cyttsp_spi_resume(struct spi_device *spi)
+{
+	return cyttsp_resume(dev_get_drvdata(&spi->dev));
+}
+#endif
+
+static struct spi_driver cyttsp_spi_driver = {
+	.driver = {
+		.name = CY_SPI_NAME,
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_spi_probe,
+	.remove = __devexit_p(cyttsp_spi_remove),
+#ifdef CONFIG_PM
+	.suspend = cyttsp_spi_suspend,
+	.resume = cyttsp_spi_resume,
+#endif
+};
+
+static int __init cyttsp_spi_init(void)
+{
+	return spi_register_driver(&cyttsp_spi_driver);
+}
+module_init(cyttsp_spi_init);
+
+static void __exit cyttsp_spi_exit(void)
+{
+	spi_unregister_driver(&cyttsp_spi_driver);
+}
+module_exit(cyttsp_spi_exit);
+
+MODULE_ALIAS("spi:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+
-- 
1.7.2.1


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-11-09 18:25 ` [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
@ 2010-11-15 16:46   ` Henrik Rydberg
  2010-11-19 17:39     ` Kevin McNeely
  2010-12-02  0:34   ` Dmitry Torokhov
  1 sibling, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2010-11-15 16:46 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Simtec Linux Team, Luotao Fu, linux-input,
	linux-kernel

On 11/09/2010 07:25 PM, Kevin McNeely wrote:

> Initial release of Cypress TTSP Gen3 Core Driver.
> Core Driver includes platform data definition file,
> core driver definition file, and core touchscreen
> touch handling of device data. Generates
> multi-touch input events.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>

> ---


Thanks for your submission. Please find comments on MT inline. On a general
note, it is strongly recommended that this driver be converted to the MT slots
(type B) protocol.

> +
> +/* TrueTouch Standard Product Gen3 interface definition */
> +struct cyttsp_xydata {
> +	u8 hst_mode;
> +	u8 tt_mode;
> +	u8 tt_stat;
> +	struct cyttsp_touch tch1;
> +	u8 touch12_id;
> +	struct cyttsp_touch tch2;
> +	u8 gest_cnt;
> +	u8 gest_id;
> +	struct cyttsp_touch tch3;
> +	u8 touch34_id;
> +	struct cyttsp_touch tch4;
> +	u8 tt_undef[3];
> +	u8 gest_set;


I take it the gesture functionality is not in use in this driver?

> +	u8 tt_reserved;
> +};
> +
> +
> +struct cyttsp_tch {
> +	struct cyttsp_touch *tch;
> +	u8 *id;
> +};


Given how this mapping is used, it could possibly be dropped altogether. See
further comment on cyttsp_init_tch_map().

> +

> +struct cyttsp_trk {
> +	u8 tch;
> +	u8 w;


It seems the device does not report contact width, so it is better not reported
at all.

> +	u16 x;
> +	u16 y;
> +	u8 z;
> +};
> +
> +struct cyttsp {
> +	struct device *dev;
> +	int irq;
> +	struct input_dev *input;
> +	struct mutex mutex;
> +	char phys[32];
> +	struct bus_type *bus_type;
> +	struct cyttsp_platform_data *platform_data;
> +	struct cyttsp_xydata xy_data;
> +	struct cyttsp_bootloader_data bl_data;
> +	struct cyttsp_sysinfo_data sysinfo_data;
> +	struct cyttsp_trk prv_trk[CY_NUM_TRK_ID];


Apart from the ids, what information is used from the previous frame?

> +static int cyttsp_gesture_setup(struct cyttsp *ts)
> +{
> +	int retval;
> +	u8 gesture_setup;
> +
> +	/* Init gesture; active distance setup */
> +	gesture_setup = ts->platform_data->gest_set;
> +	retval = ttsp_write_block_data(ts, CY_REG_GEST_SET,
> +		sizeof(gesture_setup), &gesture_setup);
> +
> +	return retval;
> +}


What does this initialization actually do?

> +
> +static void cyttsp_init_tch_map(struct cyttsp *ts)
> +{
> +	ts->tch_map[0].tch = &ts->xy_data.tch1;
> +	ts->tch_map[0].id = &ts->xy_data.touch12_id;
> +	ts->tch_map[1].tch = &ts->xy_data.tch2;
> +	ts->tch_map[1].id = &ts->xy_data.touch12_id;
> +	ts->tch_map[2].tch = &ts->xy_data.tch3;
> +	ts->tch_map[2].id = &ts->xy_data.touch34_id;
> +	ts->tch_map[3].tch = &ts->xy_data.tch4;
> +	ts->tch_map[3].id = &ts->xy_data.touch34_id;
> +}


Calling cyttsp_get_xydata() four times with special arguments would make this
function unnecessary.

> +
> +static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
> +{
> +	u8 id;
> +	u8 cnt = 0;
> +
> +	/* terminate any previous touch where the track
> +	 * is missing from the current event
> +	 */
> +	for (id = 0; id < CY_NUM_TRK_ID; id++) {
> +		if (t->cur_trk[id].tch) {
> +			/* put active current track data */
> +			input_report_abs(ts->input,
> +				ABS_MT_TRACKING_ID, id);

> +			input_report_abs(ts->input,
> +				ABS_MT_WIDTH_MAJOR, t->cur_trk[id].w);


This value does not seem to be reported by the device and should be dropped.

> +			input_report_abs(ts->input,
> +				ABS_MT_POSITION_X, t->cur_trk[id].x);
> +			input_report_abs(ts->input,
> +				ABS_MT_POSITION_Y, t->cur_trk[id].y);
> +			input_report_abs(ts->input,
> +				ABS_MT_TOUCH_MAJOR, t->cur_trk[id].z);
> +			input_mt_sync(ts->input);
> +
> +			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d\n",
> +				__func__,
> +				t->cur_trk[id].x,
> +				t->cur_trk[id].y,
> +				t->cur_trk[id].z);
> +			/* save current track data into previous track data */
> +			ts->prv_trk[id] = t->cur_trk[id];
> +			cnt++;
> +		} else if (ts->prv_trk[id].tch) {
> +			/* put lift-off previous track data */
> +			input_report_abs(ts->input,
> +				ABS_MT_TRACKING_ID, id);


Reporting tracking id here unfortunately does not work very well. With the type
A protocol, ids not reported will automatically be removed, and

> +			input_report_abs(ts->input,
> +				ABS_MT_WIDTH_MAJOR, ts->prv_trk[id].w);
> +			input_report_abs(ts->input,
> +				ABS_MT_POSITION_X, ts->prv_trk[id].x);
> +			input_report_abs(ts->input,
> +				ABS_MT_POSITION_Y, ts->prv_trk[id].y);
> +			input_report_abs(ts->input,
> +				ABS_MT_TOUCH_MAJOR, CY_NTCH);


checking for zero touch like this only applies for drivers not reporting
tracking id.

> +			input_mt_sync(ts->input);
> +
> +			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d lift-off\n",
> +				__func__,
> +				ts->prv_trk[id].x,
> +				ts->prv_trk[id].y,
> +				CY_NTCH);
> +			ts->prv_trk[id].tch = CY_NTCH;
> +			cnt++;
> +		}
> +	}
> +
> +	/* signal the view motion event */
> +	if (cnt)
> +		input_sync(ts->input);
> +}


Since the device does its own tracking, the driver would benefit greatly from
using the type B protocol.

> +static int cyttsp_xy_worker(struct cyttsp *ts)
> +{
> +	u8 cur_tch = 0;
> +	u8 tch;
> +	struct cyttsp_track_data trk;
> +
> +	/* get event data from CYTTSP device */
> +	if (ttsp_read_block_data(ts,
> +		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
> +		return 0;
> +
> +	/* touch extension handling */
> +	if (ttsp_tch_ext(ts, &ts->xy_data))
> +		return 0;
> +
> +	/* provide flow control handshake */
> +	if (ts->platform_data->use_hndshk)
> +		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
> +			return 0;
> +
> +	cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
> +
> +	if (ts->bus_ops->power_state == CY_IDLE_STATE)
> +		return 0;
> +	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
> +		return -1;
> +	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
> +		/* terminate all active tracks */
> +		cur_tch = CY_NTCH;
> +		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
> +	} else if (cur_tch > CY_NUM_TCH_ID) {
> +		/* terminate all active tracks */
> +		cur_tch = CY_NTCH;
> +		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
> +	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
> +		/* terminate all active tracks */
> +		cur_tch = CY_NTCH;
> +		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
> +	}
> +
> +	/* process the touches */
> +	cyttsp_init_cur_trks(&trk);
> +
> +	for (tch = 0; tch < cur_tch; tch++) {
> +		cyttsp_get_xydata(ts, &trk,
> +			tch & 0x01 ?
> +			(*(ts->tch_map[tch].id) & 0x0F) :
> +			(*(ts->tch_map[tch].id) & 0xF0) >> 4,
> +			CY_SMALL_TOOL_WIDTH,

> +			be16_to_cpu((ts->tch_map[tch].tch)->x),
> +			be16_to_cpu((ts->tch_map[tch].tch)->y),
> +			(ts->tch_map[tch].tch)->z);
> +	}


How about expanding this loop with special arguments instead?

> +/*
> + * Active distance in pixels for a gesture to be reported
> + * if set to 0, then all gesture movements are reported
> + * Valid range is 0 - 15
> + */
> +#define CY_ACT_DIST_DFLT 8
> +#define CY_ACT_DIST CY_ACT_DIST_DFLT


These do not seem to be used anywhere.

> +
> +enum cyttsp_gest {
> +	CY_GEST_GRP_NONE = 0,
> +	CY_GEST_GRP1 =	0x10,
> +	CY_GEST_GRP2 = 0x20,
> +	CY_GEST_GRP3 = 0x40,
> +	CY_GEST_GRP4 = 0x80,
> +};


Neither do these.

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-11-15 16:46   ` Henrik Rydberg
@ 2010-11-19 17:39     ` Kevin McNeely
  2010-12-01  7:22       ` Trilok Soni
  0 siblings, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2010-11-19 17:39 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Simtec Linux Team, Luotao Fu, linux-input,
	linux-kernel

Hello Henrik,

Thank you for reviewing this code submission.

I have replied to each of your comments below.

I would like to resubmit to include the changes.

Thanks and best regards,
Kevin


> -----Original Message-----
> From: Henrik Rydberg [mailto:rydberg@euromail.se]
> Sent: Monday, November 15, 2010 8:46 AM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Samuel Ortiz; Eric
Miao;
> Simtec Linux Team; Luotao Fu; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
> 
> On 11/09/2010 07:25 PM, Kevin McNeely wrote:
> 
> > Initial release of Cypress TTSP Gen3 Core Driver.
> > Core Driver includes platform data definition file,
> > core driver definition file, and core touchscreen
> > touch handling of device data. Generates
> > multi-touch input events.
> >
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> 
> > ---
> 
> 
> Thanks for your submission. Please find comments on MT inline. On a
> general
> note, it is strongly recommended that this driver be converted to the
> MT slots
> (type B) protocol.

I will resubmit with Protocol A only at this time.  I will remove the
Tracking ID's.

> 
> > +
> > +/* TrueTouch Standard Product Gen3 interface definition */
> > +struct cyttsp_xydata {
> > +	u8 hst_mode;
> > +	u8 tt_mode;
> > +	u8 tt_stat;
> > +	struct cyttsp_touch tch1;
> > +	u8 touch12_id;
> > +	struct cyttsp_touch tch2;
> > +	u8 gest_cnt;
> > +	u8 gest_id;
> > +	struct cyttsp_touch tch3;
> > +	u8 touch34_id;
> > +	struct cyttsp_touch tch4;
> > +	u8 tt_undef[3];
> > +	u8 gest_set;
> 
> 
> I take it the gesture functionality is not in use in this driver?

Correct, I will remove all instances and mentions of the gesture. The
field of interest is the active distance for touches.

> 
> > +	u8 tt_reserved;
> > +};
> > +
> > +
> > +struct cyttsp_tch {
> > +	struct cyttsp_touch *tch;
> > +	u8 *id;
> > +};
> 
> 
> Given how this mapping is used, it could possibly be dropped
> altogether. See
> further comment on cyttsp_init_tch_map().

The mapping is to allow number of touch growth with extra register
information. The mapping is to allow looping on the touch processing.

> 
> > +
> 
> > +struct cyttsp_trk {
> > +	u8 tch;
> > +	u8 w;
> 
> 
> It seems the device does not report contact width, so it is better not
> reported
> at all.

The width will be removed.

> 
> > +	u16 x;
> > +	u16 y;
> > +	u8 z;
> > +};
> > +
> > +struct cyttsp {
> > +	struct device *dev;
> > +	int irq;
> > +	struct input_dev *input;
> > +	struct mutex mutex;
> > +	char phys[32];
> > +	struct bus_type *bus_type;
> > +	struct cyttsp_platform_data *platform_data;
> > +	struct cyttsp_xydata xy_data;
> > +	struct cyttsp_bootloader_data bl_data;
> > +	struct cyttsp_sysinfo_data sysinfo_data;
> > +	struct cyttsp_trk prv_trk[CY_NUM_TRK_ID];
> 
> 
> Apart from the ids, what information is used from the previous frame?

The previous X, Y.

> 
> > +static int cyttsp_gesture_setup(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +	u8 gesture_setup;
> > +
> > +	/* Init gesture; active distance setup */
> > +	gesture_setup = ts->platform_data->gest_set;
> > +	retval = ttsp_write_block_data(ts, CY_REG_GEST_SET,
> > +		sizeof(gesture_setup), &gesture_setup);
> > +
> > +	return retval;
> > +}
> 
> 
> What does this initialization actually do?

This will be replaced with an active distance setup function, which is
the sole intent of the current gesture setup function.  We are really
just initializing the active distance field.

> 
> > +
> > +static void cyttsp_init_tch_map(struct cyttsp *ts)
> > +{
> > +	ts->tch_map[0].tch = &ts->xy_data.tch1;
> > +	ts->tch_map[0].id = &ts->xy_data.touch12_id;
> > +	ts->tch_map[1].tch = &ts->xy_data.tch2;
> > +	ts->tch_map[1].id = &ts->xy_data.touch12_id;
> > +	ts->tch_map[2].tch = &ts->xy_data.tch3;
> > +	ts->tch_map[2].id = &ts->xy_data.touch34_id;
> > +	ts->tch_map[3].tch = &ts->xy_data.tch4;
> > +	ts->tch_map[3].id = &ts->xy_data.touch34_id;
> > +}
> 
> 
> Calling cyttsp_get_xydata() four times with special arguments would
> make this
> function unnecessary.

The cyttsp_get_xydata() makes a single I2C read transaction which
contains touch information for all touches currently tracked by the
device.

> 
> > +
> > +static void handle_multi_touch(struct cyttsp_track_data *t, struct
> cyttsp *ts)
> > +{
> > +	u8 id;
> > +	u8 cnt = 0;
> > +
> > +	/* terminate any previous touch where the track
> > +	 * is missing from the current event
> > +	 */
> > +	for (id = 0; id < CY_NUM_TRK_ID; id++) {
> > +		if (t->cur_trk[id].tch) {
> > +			/* put active current track data */
> > +			input_report_abs(ts->input,
> > +				ABS_MT_TRACKING_ID, id);
> 
> > +			input_report_abs(ts->input,
> > +				ABS_MT_WIDTH_MAJOR, t->cur_trk[id].w);
> 
> 
> This value does not seem to be reported by the device and should be
> dropped.

This will be dropped.

> 
> > +			input_report_abs(ts->input,
> > +				ABS_MT_POSITION_X, t->cur_trk[id].x);
> > +			input_report_abs(ts->input,
> > +				ABS_MT_POSITION_Y, t->cur_trk[id].y);
> > +			input_report_abs(ts->input,
> > +				ABS_MT_TOUCH_MAJOR, t->cur_trk[id].z);
> > +			input_mt_sync(ts->input);
> > +
> > +			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d\n",
> > +				__func__,
> > +				t->cur_trk[id].x,
> > +				t->cur_trk[id].y,
> > +				t->cur_trk[id].z);
> > +			/* save current track data into previous track
data
> */
> > +			ts->prv_trk[id] = t->cur_trk[id];
> > +			cnt++;
> > +		} else if (ts->prv_trk[id].tch) {
> > +			/* put lift-off previous track data */
> > +			input_report_abs(ts->input,
> > +				ABS_MT_TRACKING_ID, id);
> 
> 
> Reporting tracking id here unfortunately does not work very well. With
> the type
> A protocol, ids not reported will automatically be removed, and

This will be Protocol A only. The Track Id reporting will be removed.

> 
> > +			input_report_abs(ts->input,
> > +				ABS_MT_WIDTH_MAJOR, ts->prv_trk[id].w);
> > +			input_report_abs(ts->input,
> > +				ABS_MT_POSITION_X, ts->prv_trk[id].x);
> > +			input_report_abs(ts->input,
> > +				ABS_MT_POSITION_Y, ts->prv_trk[id].y);
> > +			input_report_abs(ts->input,
> > +				ABS_MT_TOUCH_MAJOR, CY_NTCH);
> 
> 
> checking for zero touch like this only applies for drivers not
> reporting
> tracking id.

This will now be necessary for Protocol A only.

> 
> > +			input_mt_sync(ts->input);
> > +
> > +			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d lift-
> off\n",
> > +				__func__,
> > +				ts->prv_trk[id].x,
> > +				ts->prv_trk[id].y,
> > +				CY_NTCH);
> > +			ts->prv_trk[id].tch = CY_NTCH;
> > +			cnt++;
> > +		}
> > +	}
> > +
> > +	/* signal the view motion event */
> > +	if (cnt)
> > +		input_sync(ts->input);
> > +}
> 
> 
> Since the device does its own tracking, the driver would benefit
> greatly from
> using the type B protocol.

Current requests are for Protocol A only.  Cypress will followup with a
Protocol B driver submission.

> 
> > +static int cyttsp_xy_worker(struct cyttsp *ts)
> > +{
> > +	u8 cur_tch = 0;
> > +	u8 tch;
> > +	struct cyttsp_track_data trk;
> > +
> > +	/* get event data from CYTTSP device */
> > +	if (ttsp_read_block_data(ts,
> > +		CY_REG_BASE, sizeof(struct cyttsp_xydata),
&ts->xy_data))
> > +		return 0;
> > +
> > +	/* touch extension handling */
> > +	if (ttsp_tch_ext(ts, &ts->xy_data))
> > +		return 0;
> > +
> > +	/* provide flow control handshake */
> > +	if (ts->platform_data->use_hndshk)
> > +		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
> > +			return 0;
> > +
> > +	cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
> > +
> > +	if (ts->bus_ops->power_state == CY_IDLE_STATE)
> > +		return 0;
> > +	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
> > +		return -1;
> > +	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
> > +		/* terminate all active tracks */
> > +		cur_tch = CY_NTCH;
> > +		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
> > +	} else if (cur_tch > CY_NUM_TCH_ID) {
> > +		/* terminate all active tracks */
> > +		cur_tch = CY_NTCH;
> > +		dev_dbg(ts->dev, "%s: Num touch error detected\n",
> __func__);
> > +	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
> > +		/* terminate all active tracks */
> > +		cur_tch = CY_NTCH;
> > +		dev_dbg(ts->dev, "%s: Invalid buffer detected\n",
> __func__);
> > +	}
> > +
> > +	/* process the touches */
> > +	cyttsp_init_cur_trks(&trk);
> > +
> > +	for (tch = 0; tch < cur_tch; tch++) {
> > +		cyttsp_get_xydata(ts, &trk,
> > +			tch & 0x01 ?
> > +			(*(ts->tch_map[tch].id) & 0x0F) :
> > +			(*(ts->tch_map[tch].id) & 0xF0) >> 4,
> > +			CY_SMALL_TOOL_WIDTH,
> 
> > +			be16_to_cpu((ts->tch_map[tch].tch)->x),
> > +			be16_to_cpu((ts->tch_map[tch].tch)->y),
> > +			(ts->tch_map[tch].tch)->z);
> > +	}
> 
> 
> How about expanding this loop with special arguments instead?

The mapping method is intended to hide the offset information in the
current registry and be extensible for future updates for more touches.

> 
> > +/*
> > + * Active distance in pixels for a gesture to be reported
> > + * if set to 0, then all gesture movements are reported
> > + * Valid range is 0 - 15
> > + */
> > +#define CY_ACT_DIST_DFLT 8
> > +#define CY_ACT_DIST CY_ACT_DIST_DFLT
> 
> 
> These do not seem to be used anywhere.

This will be refined and added to the code which checks for valid
operational mode.

> 
> > +
> > +enum cyttsp_gest {
> > +	CY_GEST_GRP_NONE = 0,
> > +	CY_GEST_GRP1 =	0x10,
> > +	CY_GEST_GRP2 = 0x20,
> > +	CY_GEST_GRP3 = 0x40,
> > +	CY_GEST_GRP4 = 0x80,
> > +};
> 
> 
> Neither do these.

These will be removed.

> 
> Thanks,
> Henrik

Thanks again for your review.
Best regards,
Kevin


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-11-19 17:39     ` Kevin McNeely
@ 2010-12-01  7:22       ` Trilok Soni
  2010-12-01 14:38         ` Henrik Rydberg
  0 siblings, 1 reply; 70+ messages in thread
From: Trilok Soni @ 2010-12-01  7:22 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Henrik Rydberg, Dmitry Torokhov, David Brown, Samuel Ortiz,
	Eric Miao, Simtec Linux Team, Luotao Fu, linux-input,
	linux-kernel

Hi Henrik,

On 11/19/2010 11:09 PM, Kevin McNeely wrote:
> Hello Henrik,
> 
> Thank you for reviewing this code submission.
> 
> I have replied to each of your comments below.
> 
> I would like to resubmit to include the changes.
> 
> Thanks and best regards,
> Kevin
> 
> 
>> -----Original Message-----
>> From: Henrik Rydberg [mailto:rydberg@euromail.se]
>> Sent: Monday, November 15, 2010 8:46 AM
>> To: Kevin McNeely
>> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Samuel Ortiz; Eric
> Miao;
>> Simtec Linux Team; Luotao Fu; linux-input@vger.kernel.org; linux-
>> kernel@vger.kernel.org
>> Subject: Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
>>
>> On 11/09/2010 07:25 PM, Kevin McNeely wrote:
>>
>>> Initial release of Cypress TTSP Gen3 Core Driver.
>>> Core Driver includes platform data definition file,
>>> core driver definition file, and core touchscreen
>>> touch handling of device data. Generates
>>> multi-touch input events.
>>>
>>> Signed-off-by: Kevin McNeely <kev@cypress.com>
>>
>>> ---
>>
>>
>> Thanks for your submission. Please find comments on MT inline. On a
>> general
>> note, it is strongly recommended that this driver be converted to the
>> MT slots
>> (type B) protocol.
> 
> I will resubmit with Protocol A only at this time.  I will remove the
> Tracking ID's.
> 

Any comments on this? 

---Trilok Soni

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-01  7:22       ` Trilok Soni
@ 2010-12-01 14:38         ` Henrik Rydberg
  2010-12-01 23:59           ` Kevin McNeely
  0 siblings, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2010-12-01 14:38 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Kevin McNeely, Dmitry Torokhov, David Brown, Samuel Ortiz,
	Eric Miao, Simtec Linux Team, Luotao Fu, linux-input,
	linux-kernel

>>>

>>> Thanks for your submission. Please find comments on MT inline. On a
>>> general
>>> note, it is strongly recommended that this driver be converted to the
>>> MT slots
>>> (type B) protocol.
>>
>> I will resubmit with Protocol A only at this time.  I will remove the
>> Tracking ID's.
>>
> 
> Any comments on this?


It is not optimal, but it is not wrong. If the plan is to support kernels 2.6.38
and later, I strongly recommend using the type B protocol, as already stated.

Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-01 14:38         ` Henrik Rydberg
@ 2010-12-01 23:59           ` Kevin McNeely
  2010-12-02  0:01             ` Henrik Rydberg
  0 siblings, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2010-12-01 23:59 UTC (permalink / raw)
  To: Henrik Rydberg, Trilok Soni
  Cc: Dmitry Torokhov, David Brown, Samuel Ortiz, Eric Miao,
	Simtec Linux Team, Luotao Fu, linux-input, linux-kernel

Hello Henrik,

Cypress would like to submit as Protocol A now and provide a Protocol B
update later.

May I submit the updated Core Driver with the Protocol A only (tracking
ID's removed)? The updated Core Driver also includes other changes as
you recommended.

Thank you,
Kevin

> -----Original Message-----
> From: Henrik Rydberg [mailto:rydberg@euromail.se]
> Sent: Wednesday, December 01, 2010 6:39 AM
> To: Trilok Soni
> Cc: Kevin McNeely; Dmitry Torokhov; David Brown; Samuel Ortiz; Eric
> Miao; Simtec Linux Team; Luotao Fu; linux-input@vger.kernel.org;
linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
> 
> >>>
> 
> >>> Thanks for your submission. Please find comments on MT inline. On
a
> >>> general
> >>> note, it is strongly recommended that this driver be converted to
> the
> >>> MT slots
> >>> (type B) protocol.
> >>
> >> I will resubmit with Protocol A only at this time.  I will remove
> the
> >> Tracking ID's.
> >>
> >
> > Any comments on this?
> 
> 
> It is not optimal, but it is not wrong. If the plan is to support
> kernels 2.6.38
> and later, I strongly recommend using the type B protocol, as already
> stated.
> 
> Henrik

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-01 23:59           ` Kevin McNeely
@ 2010-12-02  0:01             ` Henrik Rydberg
  0 siblings, 0 replies; 70+ messages in thread
From: Henrik Rydberg @ 2010-12-02  0:01 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Trilok Soni, Dmitry Torokhov, David Brown, Samuel Ortiz,
	Eric Miao, Simtec Linux Team, Luotao Fu, linux-input,
	linux-kernel

On 12/02/2010 12:59 AM, Kevin McNeely wrote:

> Hello Henrik,
> 
> Cypress would like to submit as Protocol A now and provide a Protocol B
> update later.
> 
> May I submit the updated Core Driver with the Protocol A only (tracking
> ID's removed)? The updated Core Driver also includes other changes as
> you recommended.


Absolutely, you are welcome.

Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-11-09 18:25 ` [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
  2010-11-15 16:46   ` Henrik Rydberg
@ 2010-12-02  0:34   ` Dmitry Torokhov
  1 sibling, 0 replies; 70+ messages in thread
From: Dmitry Torokhov @ 2010-12-02  0:34 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: David Brown, Trilok Soni, Henrik Rydberg, Samuel Ortiz,
	Eric Miao, Simtec Linux Team, Luotao Fu, linux-input,
	linux-kernel

Hi Kevin,

On Tue, Nov 09, 2010 at 10:25:17AM -0800, Kevin McNeely wrote:
>  
> +config TOUCHSCREEN_CYTTSP_CORE
> +	bool "Cypress TTSP touchscreen core"

Tristate please - i see no reason why it can't be compiled as a module.
Same goes for I2C and SPI parts.

> +	help
> +	  Say Y here if you have a Cypress TTSP touchscreen
> +	  connected to your system.
> +
> +	  If unsure, say N.
> +

To compile this driver as a module...

> +
> +/* Touch structure */
> +struct cyttsp_touch {
> +	u16 x __attribute__ ((packed));
> +	u16 y __attribute__ ((packed));

Why packed? Natural alignment will give exactly same layout.

> +
> +struct cyttsp {
> +	struct device *dev;
> +	int irq;
> +	struct input_dev *input;
> +	struct mutex mutex;
> +	char phys[32];
> +	struct bus_type *bus_type;

const.

> +	struct cyttsp_platform_data *platform_data;

const.

> +	struct cyttsp_xydata xy_data;
> +	struct cyttsp_bootloader_data bl_data;
> +	struct cyttsp_sysinfo_data sysinfo_data;
> +	struct cyttsp_trk prv_trk[CY_NUM_TRK_ID];
> +	struct cyttsp_tch tch_map[CY_NUM_TCH_ID];
> +	struct cyttsp_bus_ops *bus_ops;

const.

> +	struct timer_list to_timer;
> +	bool bl_ready;
> +};
> +
> +struct cyttsp_track_data {
> +	struct cyttsp_trk cur_trk[CY_NUM_TRK_ID];

Do you expect to extend this? Otherwise just pass around struct
cyttsp_trk *.

> +
> +static irqreturn_t cyttsp_bl_ready_irq(int irq, void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +
> +	ts->bl_ready = true;
> +	return IRQ_HANDLED;
> +}
> +
> +static int cyttsp_load_bl_regs(struct cyttsp *ts)
> +{
> +	int retval;
> +
> +	memset(&(ts->bl_data), 0, sizeof(struct cyttsp_bootloader_data));
> +
> +	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
> +		sizeof(ts->bl_data), &(ts->bl_data));
> +
> +	return retval;
> +}
> +
> +static int cyttsp_bl_app_valid(struct cyttsp *ts)
> +{
> +	int retval;
> +
> +	retval = cyttsp_load_bl_regs(ts);
> +
> +	if (retval < 0)
> +		return -ENODEV;
> +
> +	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) {
> +		if (IS_VALID_APP(ts->bl_data.bl_status)) {
> +			dev_dbg(ts->dev, "%s: App found; normal boot\n",
> +				__func__);
> +			return 0;
> +		} else {
> +			dev_dbg(ts->dev, "%s: NO APP; load firmware!!\n",
> +				__func__);
> +			return -ENODEV;
> +		}
> +	} else if (GET_HSTMODE(ts->bl_data.bl_file) == CY_OPERATE_MODE) {
> +		if (!(IS_OPERATIONAL_ERR(ts->bl_data.bl_status))) {
> +			dev_dbg(ts->dev, "%s: Operational\n",
> +				__func__);
> +			return 1;
> +		} else {
> +			dev_dbg(ts->dev, "%s: Operational failure\n",
> +				__func__);
> +			return -ENODEV;
> +		}
> +	} else {
> +		dev_dbg(ts->dev, "%s: Non-Operational failure\n",
> +			__func__);
> +			return -ENODEV;
> +	}
> +
> +}
> +
> +static bool cyttsp_wait_bl_ready(struct cyttsp *ts, int loop_delay, int max_try)
> +{
> +	int tries = 0;
> +
> +	ts->bl_ready = false;	/* wait for interrupt to set ready flag */
> +
> +	while (!ts->bl_ready && (tries++ < max_try))
> +		msleep(loop_delay);

Ewwww! wait_event_timeout() or wait_for_completion_timeout().

> +
> +static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
> +{
> +	int retval = 0;
> +
> +	if ((ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT) ||
> +		(ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT) ||
> +		(ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT)) {

Too many parens.

> +
> +static int cyttsp_soft_reset(struct cyttsp *ts)
> +{
> +	int retval;
> +	u8 cmd = CY_SOFT_RESET_MODE;
> +
> +	/* enable bootloader interrupts */
> +	retval = request_irq(ts->irq, cyttsp_bl_ready_irq,
> +		IRQF_TRIGGER_FALLING, ts->platform_data->name, ts);
> +	if (retval)
> +		return retval;
> +
> +	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
> +	if (!retval) {
> +		if (!cyttsp_wait_bl_ready(ts, 20, 100))
> +			retval = -ENODEV;
> +		else
> +			retval = 0;
> +	}

Oh, yes, this should be a completion.

> +
> +	free_irq(ts->irq, ts);
> +	return retval;
> +}
> +
> +

...

> +static void cyttsp_init_prv_trks(struct cyttsp *ts)
> +{
> +	/* init the touch structures */
> +	memset(ts->prv_trk, CY_NTCH, sizeof(ts->prv_trk));
> +}
> +
> +static void cyttsp_init_cur_trks(struct cyttsp_track_data *t)
> +{
> +	memset(t->cur_trk, CY_NTCH, sizeof(t->cur_trk));
> +}

Do we really need these helpers?

> +
> +static int cyttsp_xy_worker(struct cyttsp *ts)
> +{
> +	u8 cur_tch = 0;
> +	u8 tch;
> +	struct cyttsp_track_data trk;
> +
> +	/* get event data from CYTTSP device */
> +	if (ttsp_read_block_data(ts,
> +		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
> +		return 0;
> +
> +	/* touch extension handling */
> +	if (ttsp_tch_ext(ts, &ts->xy_data))
> +		return 0;
> +
> +	/* provide flow control handshake */
> +	if (ts->platform_data->use_hndshk)
> +		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
> +			return 0;
> +
> +	cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
> +
> +	if (ts->bus_ops->power_state == CY_IDLE_STATE)
> +		return 0;
> +	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
> +		return -1;
> +	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
> +		/* terminate all active tracks */
> +		cur_tch = CY_NTCH;
> +		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
> +	} else if (cur_tch > CY_NUM_TCH_ID) {
> +		/* terminate all active tracks */
> +		cur_tch = CY_NTCH;
> +		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
> +	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
> +		/* terminate all active tracks */
> +		cur_tch = CY_NTCH;
> +		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
> +	}
> +
> +	/* process the touches */
> +	cyttsp_init_cur_trks(&trk);
> +
> +	for (tch = 0; tch < cur_tch; tch++) {
> +		cyttsp_get_xydata(ts, &trk,
> +			tch & 0x01 ?
> +			(*(ts->tch_map[tch].id) & 0x0F) :
> +			(*(ts->tch_map[tch].id) & 0xF0) >> 4,
> +			CY_SMALL_TOOL_WIDTH,
> +			be16_to_cpu((ts->tch_map[tch].tch)->x),
> +			be16_to_cpu((ts->tch_map[tch].tch)->y),
> +			(ts->tch_map[tch].tch)->z);


You know, open-coding instead of passing so many complex arguments would
be cleaner.

> +	}
> +
> +	handle_multi_touch(&trk, ts);
> +
> +	return 0;
> +}
> +
> +static irqreturn_t cyttsp_irq(int irq, void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +	int retval;
> +
> +	retval = cyttsp_xy_worker(ts);
> +
> +	if (retval < 0) {
> +		/* TTSP device has reset back to bootloader mode
> +		 * Reset driver touch history and restore operational mode
> +		 */
> +		cyttsp_init_prv_trks(ts);
> +		retval = cyttsp_exit_bl_mode(ts);
> +		if (retval)
> +			ts->bus_ops->power_state = CY_IDLE_STATE;
> +		dev_info(ts->dev, "%s: %s\n",
> +			__func__,
> +			(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
> +			"ACTIVE" : "IDLE");
> +	}
> +	return IRQ_HANDLED;
> +}
> +
> +static int cyttsp_power_on(struct cyttsp *ts)
> +{
> +	int retval = 0;
> +
> +	ts->bus_ops->power_state = CY_IDLE_STATE;
> +
> +	retval = cyttsp_bl_app_valid(ts);
> +	if (retval < 0)
> +		goto bypass;
> +	else if (retval > 0) {
> +		retval = cyttsp_soft_reset(ts);
> +		if (retval < 0)
> +			goto bypass;
> +	}
> +
> +	retval = cyttsp_exit_bl_mode(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	retval = cyttsp_set_sysinfo_mode(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	retval = cyttsp_set_sysinfo_regs(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	retval = cyttsp_set_operational_mode(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	/* enable touch interrupts */
> +	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
> +		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> +		ts->platform_data->name, ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	/* init gesture setup; required for active distance */
> +	retval = cyttsp_gesture_setup(ts);
> +
> +bypass:
> +	if (!retval)
> +		ts->bus_ops->power_state = CY_ACTIVE_STATE;
> +
> +	dev_info(ts->dev, "%s: %s\n",
> +		__func__,
> +		(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
> +		"ACTIVE" : "IDLE");
> +	return retval;
> +}
> +
> +#ifdef CONFIG_PM
> +int cyttsp_resume(void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +	int retval = 0;
> +	struct cyttsp_xydata xydata;
> +
> +	if (ts->platform_data->use_sleep && (ts->bus_ops->power_state !=
> +		CY_ACTIVE_STATE)) {
> +		if (ts->platform_data->wakeup) {
> +			retval = ts->platform_data->wakeup();
> +			if (retval < 0)
> +				dev_dbg(ts->dev, "%s: Error, wakeup failed!\n",
> +					__func__);
> +		} else {
> +			dev_dbg(ts->dev, "%s: Error, wakeup not implemented "
> +				"(check board file).\n", __func__);
> +			retval = -ENOSYS;
> +		}
> +		if (!(retval < 0)) {
> +			retval = ttsp_read_block_data(ts, CY_REG_BASE,
> +				sizeof(xydata), &xydata);
> +			if (!(retval < 0) && !GET_HSTMODE(xydata.hst_mode))
> +				ts->bus_ops->power_state = CY_ACTIVE_STATE;
> +		}
> +	}
> +	dev_dbg(ts->dev, "%s: Wake Up %s\n", __func__,
> +		(retval < 0) ? "FAIL" : "PASS");
> +	return retval;
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_resume);
> +
> +int cyttsp_suspend(void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +	u8 sleep_mode = 0;
> +	int retval = 0;
> +
> +	if (ts->platform_data->use_sleep &&
> +		(ts->bus_ops->power_state == CY_ACTIVE_STATE)) {
> +		sleep_mode = CY_DEEP_SLEEP_MODE;
> +		retval = ttsp_write_block_data(ts,
> +			CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
> +		if (!(retval < 0))
> +			ts->bus_ops->power_state = CY_SLEEP_STATE;
> +	}
> +	dev_dbg(ts->dev, "%s: Sleep Power state is %s\n", __func__,
> +		(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
> +		"ACTIVE" :
> +		((ts->bus_ops->power_state == CY_SLEEP_STATE) ?
> +		"SLEEP" : "LOW POWER"));
> +	return retval;
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_suspend);
> +#endif
> +
> +int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
> +	struct device *dev, void *handle)
> +{
> +	struct input_dev *input_device;
> +	struct cyttsp *ts;
> +	int retval = 0;
> +
> +	if ((dev == NULL) || (bus_ops == NULL))
> +		goto error_alloc_data;
> +
> +	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> +	if (ts == NULL) {
> +		dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
> +		retval = -ENOMEM;
> +		goto error_alloc_data;
> +	}
> +	mutex_init(&ts->mutex);
> +	ts->dev = dev;
> +	ts->platform_data = dev->platform_data;
> +	ts->bus_ops = bus_ops;
> +	ts->platform_data->dev = ts->dev;
> +
> +	if (ts->platform_data->init) {
> +		retval = ts->platform_data->init(ts->platform_data, 1);
> +		if (retval) {
> +			dev_dbg(ts->dev, "%s: Error, platform init failed!\n",
> +				__func__);
> +			retval = -EIO;
> +			goto error_init;
> +		}
> +	}
> +
> +	ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
> +	if (ts->irq <= 0) {
> +		dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
> +			__func__);
> +			retval = -EIO;
> +			goto error_init;
> +	}
> +
> +	/* Create the input device and register it. */
> +	input_device = input_allocate_device();
> +	if (!input_device) {
> +		retval = -ENOMEM;
> +		dev_dbg(ts->dev, "%s: Error, failed to allocate input device\n",
> +			__func__);
> +			retval = -ENODEV;
> +		goto error_input_allocate_device;
> +	}
> +
> +	ts->input = input_device;
> +	input_device->name = ts->platform_data->name;
> +	input_device->phys = ts->phys;
> +	input_device->dev.parent = ts->dev;
> +	ts->bus_type = bus_ops->dev->bus;
> +
> +	cyttsp_init_tch_map(ts);
> +	cyttsp_init_prv_trks(ts);
> +
> +	__set_bit(EV_SYN, input_device->evbit);
> +	__set_bit(EV_KEY, input_device->evbit);
> +	__set_bit(EV_ABS, input_device->evbit);
> +
> +	input_set_abs_params(input_device, ABS_MT_POSITION_X,
> +		0, ts->platform_data->maxx, 0, 0);
> +	input_set_abs_params(input_device, ABS_MT_POSITION_Y,
> +		0, ts->platform_data->maxy, 0, 0);
> +	input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
> +		0, CY_MAXZ, 0, 0);
> +	input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR,
> +		0, CY_LARGE_TOOL_WIDTH, 0, 0);
> +	input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
> +		0, CY_NUM_TRK_ID, 0, 0);
> +
> +	retval = input_register_device(input_device);
> +	if (retval) {
> +		dev_dbg(ts->dev, "%s: Error, failed to register input device\n",
> +			__func__);
> +			retval = -ENODEV;
> +		goto error_input_register_device;
> +	}
> +
> +	retval = cyttsp_power_on(ts);

This should probably go into input->open() method. No need to power up
until there are users.

> +
> +	if (retval < 0) {
> +		dev_dbg(ts->dev, "%s: Error, power on failed!\n", __func__);
> +		retval = -ENODEV;
> +		goto error_power_on;
> +	}
> +
> +	handle = ts;
> +	goto no_error;
> +
> +error_power_on:
> +	free_irq(ts->irq, ts);
> +error_input_register_device:
> +	input_unregister_device(input_device);
> +error_input_allocate_device:
> +	if (ts->platform_data->init)
> +		ts->platform_data->init(ts->platform_data, 0);
> +error_init:
> +	mutex_destroy(&ts->mutex);
> +	kfree(ts);
> +error_alloc_data:
> +	handle = NULL;

Why?

Btw, have it return struct cyttsp * and check for errors with IS_ERR().

> +no_error:
> +	return retval;
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_core_init);
> +
> +/* registered in driver struct */
> +void cyttsp_core_release(void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +
> +	mutex_destroy(&ts->mutex);
> +	free_irq(ts->irq, ts);
> +	input_unregister_device(ts->input);
> +	if (ts->platform_data->init)
> +		ts->platform_data->init(ts->platform_data, 0);

Maybe call it platform_data->exit()?

> +	kfree(ts);
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_core_release);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
> +MODULE_AUTHOR("Cypress");
> +
> diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
> new file mode 100644
> index 0000000..43fe438
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp_core.h
> @@ -0,0 +1,55 @@
> +/* Header file for:
> + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
> + * For use with Cypress Txx3xx parts.
> + * Supported parts include:
> + * CY8CTST341
> + * CY8CTMA340
> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
> + *
> + */
> +
> +
> +#ifndef __CYTTSP_CORE_H__
> +#define __CYTTSP_CORE_H__
> +
> +#include <linux/kernel.h>
> +#include <linux/input/cyttsp.h>
> +
> +#define CY_NUM_RETRY                4 /* max number of retries for read ops */
> +
> +
> +struct cyttsp_bus_ops {
> +	s32 (*write)(void *handle, u8 addr, u8 length, const void *values);
> +	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
> +	s32 (*ext)(void *handle, void *values);
> +	struct device *dev;
> +	enum cyttsp_powerstate power_state;
> +};
> +
> +int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
> +	struct device *dev, void *handle);
> +
> +void cyttsp_core_release(void *handle);
> +#ifdef CONFIG_PM
> +int cyttsp_resume(void *handle);
> +int cyttsp_suspend(void *handle);
> +#endif
> +
> +#endif /* __CYTTSP_CORE_H__ */
> diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
> new file mode 100644
> index 0000000..5280252
> --- /dev/null
> +++ b/include/linux/input/cyttsp.h
> @@ -0,0 +1,78 @@
> +/* Header file for:
> + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
> + * For use with Cypress Txx3xx parts.
> + * Supported parts include:
> + * CY8CTST341
> + * CY8CTMA340
> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
> + *
> + */
> +#ifndef _CYTTSP_H_
> +#define _CYTTSP_H_
> +
> +#define CY_SPI_NAME "cyttsp-spi"
> +#define CY_I2C_NAME "cyttsp-i2c"
> +/* Active Power state scanning/processing refresh interval */
> +#define CY_ACT_INTRVL_DFLT 0x00
> +/* touch timeout for the Active power */
> +#define CY_TCH_TMOUT_DFLT 0xFF
> +/* Low Power state scanning/processing refresh interval */
> +#define CY_LP_INTRVL_DFLT 0x0A
> +/*
> + * Active distance in pixels for a gesture to be reported
> + * if set to 0, then all gesture movements are reported
> + * Valid range is 0 - 15
> + */
> +#define CY_ACT_DIST_DFLT 8
> +#define CY_ACT_DIST CY_ACT_DIST_DFLT
> +
> +enum cyttsp_gest {
> +	CY_GEST_GRP_NONE = 0,
> +	CY_GEST_GRP1 =	0x10,
> +	CY_GEST_GRP2 = 0x20,
> +	CY_GEST_GRP3 = 0x40,
> +	CY_GEST_GRP4 = 0x80,
> +};
> +
> +enum cyttsp_powerstate {
> +	CY_IDLE_STATE,
> +	CY_ACTIVE_STATE,
> +	CY_LOW_PWR_STATE,
> +	CY_SLEEP_STATE,
> +};
> +
> +struct cyttsp_platform_data {
> +	struct device *dev;

Hm, platform data might be shared, not a good idea to have device
pointer here.

> +	u32 maxx;
> +	u32 maxy;
> +	unsigned use_hndshk:1;

bool.

> +	unsigned use_sleep:1;

bool.

> +	u8 gest_set;	/* Active distance */
> +	u8 act_intrvl;  /* Active refresh interval; ms */
> +	u8 tch_tmout;   /* Active touch timeout; ms */
> +	u8 lp_intrvl;   /* Low power refresh interval; ms */
> +	int (*wakeup)(void);
> +	int (*init)(struct cyttsp_platform_data *, int on_off);
> +	char *name;
> +	s16 irq_gpio;
> +	u8 *bl_keys;
> +};
> +

Thanks.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v2] touchscreen Cypress TTSP G3 MTDEV Core Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (4 preceding siblings ...)
  2010-11-09 18:25 ` [PATCH] spi: Cypress TTSP G3 MTDEV SPI " Kevin McNeely
@ 2010-12-04  2:06 ` Kevin McNeely
  2010-12-05  9:11   ` Henrik Rydberg
  2010-12-04  2:06 ` [v2] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver Kevin McNeely
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2010-12-04  2:06 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Henrik Rydberg, Samuel Ortiz, Eric Miao, Luotao Fu, linux-input,
	linux-kernel

Amended version of Cypress TTSP Gen3 Core Driver.
Core Driver includes platform data definition file,
core driver definition file, and core touchscreen
touch handling of device data. Generates
multi-touch input events.
Amendments include changes recommended by reviewers
of initial version.  Kconfig is for I2C and SPI modules
including the core.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Kconfig       |   24 ++-
 drivers/input/touchscreen/Makefile      |    2 +-
 drivers/input/touchscreen/cyttsp_core.c |  442 ++++++++++++++++---------------
 drivers/input/touchscreen/cyttsp_core.h |    5 +-
 include/linux/input/cyttsp.h            |   35 +--
 5 files changed, 263 insertions(+), 245 deletions(-)

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index ee5a31b..14aa5d0 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -126,12 +126,34 @@ config TOUCHSCREEN_CY8CTMG110
 
 config TOUCHSCREEN_CYTTSP_CORE
 	bool "Cypress TTSP touchscreen core"
+	depends on TOUCHSCREEN_CYTTSP_I2C || TOUCHSCREEN_CYTTSP_SPI
+	help
+	  Always activated for Cypress TTSP touchscreen
+
+config TOUCHSCREEN_CYTTSP_I2C
+	tristate "Cypress TTSP i2c touchscreen"
+	depends on I2C
 	help
 	  Say Y here if you have a Cypress TTSP touchscreen
-	  connected to your system.
+	  connected to your system with an I2C interface.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp-i2c.
+
+config TOUCHSCREEN_CYTTSP_SPI
+	tristate "Cypress TTSP spi touchscreen"
+	depends on SPI_MASTER
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your  with an SPI interface.
 
 	  If unsure, say N.
 
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp-spi.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index f629af9..b6f1ba8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 99fd316..72b9be9 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -70,12 +70,14 @@
 #define CY_SMALL_TOOL_WIDTH         10
 #define CY_LARGE_TOOL_WIDTH         255
 #define CY_REG_BASE                 0x00
-#define CY_REG_GEST_SET             0x1E
+#define CY_REG_ACT_DIST             0x1E
 #define CY_REG_ACT_INTRVL           0x1D
 #define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
 #define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
 #define CY_MAXZ                     255
-#define CY_DELAY_SYSINFO            20 /* ms */
+#define CY_DELAY_DFLT               20 /* ms */
+#define CY_DELAY_MAX                (500/CY_DELAY_DFLT) /* half second */
+#define CY_ACT_DIST_DFLT            0xF8
 #define CY_HNDSHK_BIT               0x80
 /* device mode bits */
 #define CY_OPERATE_MODE             0x00
@@ -87,8 +89,8 @@
 
 /* Touch structure */
 struct cyttsp_touch {
-	u16 x __attribute__ ((packed));
-	u16 y __attribute__ ((packed));
+	u8 x[2];
+	u8 y[2];
 	u8 z;
 };
 
@@ -106,7 +108,7 @@ struct cyttsp_xydata {
 	u8 touch34_id;
 	struct cyttsp_touch tch4;
 	u8 tt_undef[3];
-	u8 gest_set;
+	u8 act_dist;
 	u8 tt_reserved;
 };
 
@@ -160,8 +162,7 @@ struct cyttsp_tch {
 };
 
 struct cyttsp_trk {
-	u8 tch;
-	u8 w;
+	bool tch;
 	u16 x;
 	u16 y;
 	u8 z;
@@ -173,16 +174,17 @@ struct cyttsp {
 	struct input_dev *input;
 	struct mutex mutex;
 	char phys[32];
-	struct bus_type *bus_type;
-	struct cyttsp_platform_data *platform_data;
+	const struct bus_type *bus_type;
+	const struct cyttsp_platform_data *platform_data;
+	struct cyttsp_bus_ops *bus_ops;
 	struct cyttsp_xydata xy_data;
 	struct cyttsp_bootloader_data bl_data;
 	struct cyttsp_sysinfo_data sysinfo_data;
 	struct cyttsp_trk prv_trk[CY_NUM_TRK_ID];
 	struct cyttsp_tch tch_map[CY_NUM_TCH_ID];
-	struct cyttsp_bus_ops *bus_ops;
 	struct timer_list to_timer;
-	bool bl_ready;
+	struct completion bl_ready;
+	enum cyttsp_powerstate power_state;
 };
 
 struct cyttsp_track_data {
@@ -237,14 +239,6 @@ static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
 	return retval;
 }
 
-static irqreturn_t cyttsp_bl_ready_irq(int irq, void *handle)
-{
-	struct cyttsp *ts = handle;
-
-	ts->bl_ready = true;
-	return IRQ_HANDLED;
-}
-
 static int cyttsp_load_bl_regs(struct cyttsp *ts)
 {
 	int retval;
@@ -294,25 +288,10 @@ static int cyttsp_bl_app_valid(struct cyttsp *ts)
 
 }
 
-static bool cyttsp_wait_bl_ready(struct cyttsp *ts, int loop_delay, int max_try)
-{
-	int tries = 0;
-
-	ts->bl_ready = false;	/* wait for interrupt to set ready flag */
-
-	while (!ts->bl_ready && (tries++ < max_try))
-		msleep(loop_delay);
-
-	if (tries < max_try)
-		return true;
-	else
-		return false;
-}
-
 static int cyttsp_exit_bl_mode(struct cyttsp *ts)
 {
 	int retval;
-	int tries = 0;
+	int tries;
 	u8 bl_cmd[sizeof(bl_command)];
 
 	memcpy(bl_cmd, bl_command, sizeof(bl_command));
@@ -332,12 +311,17 @@ static int cyttsp_exit_bl_mode(struct cyttsp *ts)
 	if (retval < 0)
 		return retval;
 
+	/* wait for TTSP Device to complete switch to Operational mode */
+	tries = 0;
 	do {
-		msleep(500);
+		msleep(CY_DELAY_DFLT);
 		retval = cyttsp_load_bl_regs(ts);
-	} while (GET_BOOTLOADERMODE(ts->bl_data.bl_status) &&
-		tries++ < 10 &&
-		!(retval < 0));
+	} while (!((retval == 0) &&
+		!GET_BOOTLOADERMODE(ts->bl_data.bl_status)) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check bl ready tries=%d ret=%d stat=%02X\n",
+		__func__, tries, retval, ts->bl_data.bl_status);
 
 	if (retval < 0)
 		return retval;
@@ -350,6 +334,7 @@ static int cyttsp_exit_bl_mode(struct cyttsp *ts)
 static int cyttsp_set_operational_mode(struct cyttsp *ts)
 {
 	int retval;
+	int tries;
 	u8 cmd = CY_OPERATE_MODE;
 
 	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
@@ -358,7 +343,17 @@ static int cyttsp_set_operational_mode(struct cyttsp *ts)
 		return retval;
 
 	/* wait for TTSP Device to complete switch to Operational mode */
-	msleep(500);
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = ttsp_read_block_data(ts, CY_REG_BASE,
+			sizeof(ts->xy_data), &(ts->xy_data));
+	} while (!((retval == 0) &&
+		(ts->xy_data.act_dist == CY_ACT_DIST_DFLT)) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check op ready tries=%d ret=%d dist=%02X\n",
+		__func__, tries, retval, ts->xy_data.act_dist);
 
 	return retval;
 }
@@ -366,6 +361,7 @@ static int cyttsp_set_operational_mode(struct cyttsp *ts)
 static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
 {
 	int retval;
+	int tries;
 	u8 cmd = CY_SYSINFO_MODE;
 
 	memset(&(ts->sysinfo_data), 0, sizeof(struct cyttsp_sysinfo_data));
@@ -375,11 +371,19 @@ static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
 	if (retval < 0)
 		return retval;
 
-	msleep(500);
-
 	/* read sysinfo registers */
-	retval = ttsp_read_block_data(ts, CY_REG_BASE,
-		sizeof(ts->sysinfo_data), &(ts->sysinfo_data));
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = ttsp_read_block_data(ts, CY_REG_BASE,
+			sizeof(ts->sysinfo_data), &(ts->sysinfo_data));
+	} while (!((retval == 0) &&
+		!((ts->sysinfo_data.tts_verh == 0) &&
+		(ts->sysinfo_data.tts_verl == 0))) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check sysinfo ready tries=%d ret=%d\n",
+		__func__, tries, retval);
 
 	dev_info(ts->dev, "%s: tv=%02X%02X ai=0x%02X%02X "
 		"av=0x%02X%02X ci=0x%02X%02X%02X\n", "cyttsp",
@@ -396,9 +400,9 @@ static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
 {
 	int retval = 0;
 
-	if ((ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT) ||
-		(ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT) ||
-		(ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT)) {
+	if (ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT ||
+		ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT ||
+		ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT) {
 
 		u8 intrvl_ray[3];
 
@@ -411,7 +415,7 @@ static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
 				CY_REG_ACT_INTRVL,
 				sizeof(intrvl_ray), intrvl_ray);
 
-		msleep(CY_DELAY_SYSINFO);
+		msleep(CY_DELAY_DFLT);
 	}
 
 	return retval;
@@ -422,37 +426,36 @@ static int cyttsp_soft_reset(struct cyttsp *ts)
 	int retval;
 	u8 cmd = CY_SOFT_RESET_MODE;
 
-	/* enable bootloader interrupts */
-	retval = request_irq(ts->irq, cyttsp_bl_ready_irq,
-		IRQF_TRIGGER_FALLING, ts->platform_data->name, ts);
-	if (retval)
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (retval < 0)
 		return retval;
 
-	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
-	if (!retval) {
-		if (!cyttsp_wait_bl_ready(ts, 20, 100))
-			retval = -ENODEV;
-		else
-			retval = 0;
-	}
+	/* wait for interrupt to set ready completion */
+	INIT_COMPLETION(ts->bl_ready);
+
+	retval = wait_for_completion_interruptible_timeout(&ts->bl_ready,
+		msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
+
+	if (retval > 0)
+		retval = 0;
 
-	free_irq(ts->irq, ts);
 	return retval;
 }
 
-static int cyttsp_gesture_setup(struct cyttsp *ts)
+static int cyttsp_act_dist_setup(struct cyttsp *ts)
 {
 	int retval;
-	u8 gesture_setup;
+	u8 act_dist_setup;
 
 	/* Init gesture; active distance setup */
-	gesture_setup = ts->platform_data->gest_set;
-	retval = ttsp_write_block_data(ts, CY_REG_GEST_SET,
-		sizeof(gesture_setup), &gesture_setup);
+	act_dist_setup = ts->platform_data->act_dist;
+	retval = ttsp_write_block_data(ts, CY_REG_ACT_DIST,
+		sizeof(act_dist_setup), &act_dist_setup);
 
 	return retval;
 }
 
+/* map pointers to touch information to allow loop on get xy_data */
 static void cyttsp_init_tch_map(struct cyttsp *ts)
 {
 	ts->tch_map[0].tch = &ts->xy_data.tch1;
@@ -465,17 +468,6 @@ static void cyttsp_init_tch_map(struct cyttsp *ts)
 	ts->tch_map[3].id = &ts->xy_data.touch34_id;
 }
 
-static void cyttsp_init_prv_trks(struct cyttsp *ts)
-{
-	/* init the touch structures */
-	memset(ts->prv_trk, CY_NTCH, sizeof(ts->prv_trk));
-}
-
-static void cyttsp_init_cur_trks(struct cyttsp_track_data *t)
-{
-	memset(t->cur_trk, CY_NTCH, sizeof(t->cur_trk));
-}
-
 static int cyttsp_hndshk(struct cyttsp *ts, u8 hst_mode)
 {
 	int retval;
@@ -491,7 +483,7 @@ static int cyttsp_hndshk(struct cyttsp *ts, u8 hst_mode)
 	return retval;
 }
 
-static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
+static void handle_multi_touch(struct cyttsp_trk *cur_trk, struct cyttsp *ts)
 {
 	u8 id;
 	u8 cnt = 0;
@@ -500,35 +492,27 @@ static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
 	 * is missing from the current event
 	 */
 	for (id = 0; id < CY_NUM_TRK_ID; id++) {
-		if (t->cur_trk[id].tch) {
+		if (cur_trk[id].tch) {
 			/* put active current track data */
 			input_report_abs(ts->input,
-				ABS_MT_TRACKING_ID, id);
-			input_report_abs(ts->input,
-				ABS_MT_WIDTH_MAJOR, t->cur_trk[id].w);
+				ABS_MT_POSITION_X, cur_trk[id].x);
 			input_report_abs(ts->input,
-				ABS_MT_POSITION_X, t->cur_trk[id].x);
+				ABS_MT_POSITION_Y, cur_trk[id].y);
 			input_report_abs(ts->input,
-				ABS_MT_POSITION_Y, t->cur_trk[id].y);
-			input_report_abs(ts->input,
-				ABS_MT_TOUCH_MAJOR, t->cur_trk[id].z);
+				ABS_MT_TOUCH_MAJOR, cur_trk[id].z);
 			input_mt_sync(ts->input);
 
-			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d\n",
-				__func__,
-				t->cur_trk[id].x,
-				t->cur_trk[id].y,
-				t->cur_trk[id].z);
-			/* save current track data into previous track data */
-			ts->prv_trk[id] = t->cur_trk[id];
+			dev_dbg(ts->dev, "%s: MT% 2d: X=%d Y=%d Z=%d\n",
+				__func__, id,
+				cur_trk[id].x,
+				cur_trk[id].y,
+				cur_trk[id].z);
+			/* save current touch xy_data as previous track data */
+			ts->prv_trk[id] = cur_trk[id];
 			cnt++;
 		} else if (ts->prv_trk[id].tch) {
 			/* put lift-off previous track data */
 			input_report_abs(ts->input,
-				ABS_MT_TRACKING_ID, id);
-			input_report_abs(ts->input,
-				ABS_MT_WIDTH_MAJOR, ts->prv_trk[id].w);
-			input_report_abs(ts->input,
 				ABS_MT_POSITION_X, ts->prv_trk[id].x);
 			input_report_abs(ts->input,
 				ABS_MT_POSITION_Y, ts->prv_trk[id].y);
@@ -536,11 +520,12 @@ static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
 				ABS_MT_TOUCH_MAJOR, CY_NTCH);
 			input_mt_sync(ts->input);
 
-			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d lift-off\n",
-				__func__,
+			dev_dbg(ts->dev, "%s: MT% 2d: X=%d Y=%d Z=%d liftoff\n",
+				__func__, id,
 				ts->prv_trk[id].x,
 				ts->prv_trk[id].y,
 				CY_NTCH);
+			/* clear previous touch indication */
 			ts->prv_trk[id].tch = CY_NTCH;
 			cnt++;
 		}
@@ -551,27 +536,21 @@ static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
 		input_sync(ts->input);
 }
 
-static void cyttsp_get_xydata(struct cyttsp *ts,
-	struct cyttsp_track_data *t,
-	u8 id, u8 w, u16 x, u16 y, u8 z)
-{
-	struct cyttsp_trk *trk;
-
-	trk = &(t->cur_trk[id]);
-	trk->tch = CY_TCH;
-	trk->w = w;
-	trk->x = x;
-	trk->y = y;
-	trk->z = z;
-}
-
+/* read xy_data for all current touches */
 static int cyttsp_xy_worker(struct cyttsp *ts)
 {
 	u8 cur_tch = 0;
 	u8 tch;
-	struct cyttsp_track_data trk;
+	u8 id;
+	u8 *x;
+	u8 *y;
+	u8 z;
+	struct cyttsp_trk cur_trk[CY_NUM_TRK_ID];
 
-	/* get event data from CYTTSP device */
+	/* Get event data from CYTTSP device.
+	 * The event data includes all data
+	 * for all active touches.
+	 */
 	if (ttsp_read_block_data(ts,
 		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
 		return 0;
@@ -585,9 +564,11 @@ static int cyttsp_xy_worker(struct cyttsp *ts)
 		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
 			return 0;
 
+	/* determine number of currently active touches */
 	cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
 
-	if (ts->bus_ops->power_state == CY_IDLE_STATE)
+	/* check for any error conditions */
+	if (ts->power_state == CY_IDLE_STATE)
 		return 0;
 	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
 		return -1;
@@ -605,44 +586,70 @@ static int cyttsp_xy_worker(struct cyttsp *ts)
 		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
 	}
 
-	/* process the touches */
-	cyttsp_init_cur_trks(&trk);
+	/* clear current touch tracking structures */
+	memset(cur_trk, CY_NTCH, sizeof(cur_trk));
 
+	/* extract xy_data for all currently reported touches */
 	for (tch = 0; tch < cur_tch; tch++) {
-		cyttsp_get_xydata(ts, &trk,
-			tch & 0x01 ?
+		id = tch & 0x01 ?
 			(*(ts->tch_map[tch].id) & 0x0F) :
-			(*(ts->tch_map[tch].id) & 0xF0) >> 4,
-			CY_SMALL_TOOL_WIDTH,
-			be16_to_cpu((ts->tch_map[tch].tch)->x),
-			be16_to_cpu((ts->tch_map[tch].tch)->y),
-			(ts->tch_map[tch].tch)->z);
+			(*(ts->tch_map[tch].id) & 0xF0) >> 4;
+		x = (u8 *)&((ts->tch_map[tch].tch)->x);
+		y = (u8 *)&((ts->tch_map[tch].tch)->y);
+		z = (ts->tch_map[tch].tch)->z;
+		cur_trk[id].tch = CY_TCH;
+		cur_trk[id].x = ((u16)x[0] << 8) + x[1];
+		cur_trk[id].y = ((u16)y[0] << 8) + y[1];
+		cur_trk[id].z = z;
 	}
 
-	handle_multi_touch(&trk, ts);
+	/* provide input event signaling for each active touch */
+	handle_multi_touch(cur_trk, ts);
 
 	return 0;
 }
 
+static void cyttsp_pr_state(struct cyttsp *ts)
+{
+	static char *cyttsp_powerstate_string[] = {
+		"IDLE",
+		"ACTIVE",
+		"LOW_PWR",
+		"SLEEP",
+		"BOOTLOADER",
+		"INVALID"
+	};
+
+	dev_info(ts->dev, "%s: %s\n", __func__,
+		ts->power_state < CY_INVALID_STATE ?
+		cyttsp_powerstate_string[ts->power_state] :
+		"INVALID");
+}
+
 static irqreturn_t cyttsp_irq(int irq, void *handle)
 {
 	struct cyttsp *ts = handle;
 	int retval;
 
-	retval = cyttsp_xy_worker(ts);
-
-	if (retval < 0) {
-		/* TTSP device has reset back to bootloader mode
-		 * Reset driver touch history and restore operational mode
-		 */
-		cyttsp_init_prv_trks(ts);
-		retval = cyttsp_exit_bl_mode(ts);
-		if (retval)
-			ts->bus_ops->power_state = CY_IDLE_STATE;
-		dev_info(ts->dev, "%s: %s\n",
-			__func__,
-			(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
-			"ACTIVE" : "IDLE");
+	if (ts->power_state == CY_BL_STATE)
+		complete(&ts->bl_ready);
+	else {
+		/* process the touches */
+		retval = cyttsp_xy_worker(ts);
+
+		if (retval < 0) {
+			/* TTSP device has reset back to bootloader mode
+			 * Reset driver touch history and restore
+			 * operational mode
+			 */
+			memset(ts->prv_trk, CY_NTCH, sizeof(ts->prv_trk));
+			retval = cyttsp_exit_bl_mode(ts);
+			if (retval)
+				ts->power_state = CY_IDLE_STATE;
+			else
+				ts->power_state = CY_ACTIVE_STATE;
+			cyttsp_pr_state(ts);
+		}
 	}
 	return IRQ_HANDLED;
 }
@@ -651,21 +658,35 @@ static int cyttsp_power_on(struct cyttsp *ts)
 {
 	int retval = 0;
 
-	ts->bus_ops->power_state = CY_IDLE_STATE;
+	if (!ts)
+		return -ENOMEM;
+
+	ts->power_state = CY_BL_STATE;
+
+	/* enable interrupts */
+	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		ts->platform_data->name, ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_soft_reset(ts);
+	if (retval < 0)
+		goto bypass;
 
 	retval = cyttsp_bl_app_valid(ts);
 	if (retval < 0)
 		goto bypass;
-	else if (retval > 0) {
-		retval = cyttsp_soft_reset(ts);
-		if (retval < 0)
-			goto bypass;
-	}
+	else if (retval > 0)
+		goto no_bl_bypass;
 
 	retval = cyttsp_exit_bl_mode(ts);
 	if (retval < 0)
 		goto bypass;
 
+	ts->power_state = CY_IDLE_STATE;
+
+no_bl_bypass:
 	retval = cyttsp_set_sysinfo_mode(ts);
 	if (retval < 0)
 		goto bypass;
@@ -678,24 +699,16 @@ static int cyttsp_power_on(struct cyttsp *ts)
 	if (retval < 0)
 		goto bypass;
 
-	/* enable touch interrupts */
-	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
-		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-		ts->platform_data->name, ts);
+	/* init active distance */
+	retval = cyttsp_act_dist_setup(ts);
 	if (retval < 0)
 		goto bypass;
 
-	/* init gesture setup; required for active distance */
-	retval = cyttsp_gesture_setup(ts);
+	ts->power_state = CY_ACTIVE_STATE;
+	retval = 0;
 
 bypass:
-	if (!retval)
-		ts->bus_ops->power_state = CY_ACTIVE_STATE;
-
-	dev_info(ts->dev, "%s: %s\n",
-		__func__,
-		(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
-		"ACTIVE" : "IDLE");
+	cyttsp_pr_state(ts);
 	return retval;
 }
 
@@ -706,7 +719,7 @@ int cyttsp_resume(void *handle)
 	int retval = 0;
 	struct cyttsp_xydata xydata;
 
-	if (ts->platform_data->use_sleep && (ts->bus_ops->power_state !=
+	if (ts->platform_data->use_sleep && (ts->power_state !=
 		CY_ACTIVE_STATE)) {
 		if (ts->platform_data->wakeup) {
 			retval = ts->platform_data->wakeup();
@@ -722,7 +735,7 @@ int cyttsp_resume(void *handle)
 			retval = ttsp_read_block_data(ts, CY_REG_BASE,
 				sizeof(xydata), &xydata);
 			if (!(retval < 0) && !GET_HSTMODE(xydata.hst_mode))
-				ts->bus_ops->power_state = CY_ACTIVE_STATE;
+				ts->power_state = CY_ACTIVE_STATE;
 		}
 	}
 	dev_dbg(ts->dev, "%s: Wake Up %s\n", __func__,
@@ -738,51 +751,77 @@ int cyttsp_suspend(void *handle)
 	int retval = 0;
 
 	if (ts->platform_data->use_sleep &&
-		(ts->bus_ops->power_state == CY_ACTIVE_STATE)) {
+		(ts->power_state == CY_ACTIVE_STATE)) {
 		sleep_mode = CY_DEEP_SLEEP_MODE;
 		retval = ttsp_write_block_data(ts,
 			CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
 		if (!(retval < 0))
-			ts->bus_ops->power_state = CY_SLEEP_STATE;
+			ts->power_state = CY_SLEEP_STATE;
 	}
 	dev_dbg(ts->dev, "%s: Sleep Power state is %s\n", __func__,
-		(ts->bus_ops->power_state == CY_ACTIVE_STATE) ?
+		(ts->power_state == CY_ACTIVE_STATE) ?
 		"ACTIVE" :
-		((ts->bus_ops->power_state == CY_SLEEP_STATE) ?
+		((ts->power_state == CY_SLEEP_STATE) ?
 		"SLEEP" : "LOW POWER"));
 	return retval;
 }
 EXPORT_SYMBOL_GPL(cyttsp_suspend);
 #endif
 
-int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
-	struct device *dev, void *handle)
+static int cyttsp_open(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	return cyttsp_power_on(ts);
+}
+
+void cyttsp_core_release(void *handle)
+{
+	struct cyttsp *ts = handle;
+
+	if (ts) {
+		mutex_destroy(&ts->mutex);
+		free_irq(ts->irq, ts);
+		input_unregister_device(ts->input);
+		if (ts->platform_data->exit)
+			ts->platform_data->exit();
+		kfree(ts);
+	}
+}
+EXPORT_SYMBOL_GPL(cyttsp_core_release);
+
+static void cyttsp_close(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	cyttsp_core_release(ts);
+}
+
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *dev)
 {
 	struct input_dev *input_device;
-	struct cyttsp *ts;
-	int retval = 0;
+	struct cyttsp *ts = kzalloc(sizeof(*ts), GFP_KERNEL);
 
-	if ((dev == NULL) || (bus_ops == NULL))
+	if (!ts) {
+		dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
 		goto error_alloc_data;
+	}
 
-	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-	if (ts == NULL) {
-		dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
-		retval = -ENOMEM;
+	if ((dev == NULL) || (bus_ops == NULL)) {
+		kfree(ts);
 		goto error_alloc_data;
 	}
+
 	mutex_init(&ts->mutex);
 	ts->dev = dev;
 	ts->platform_data = dev->platform_data;
 	ts->bus_ops = bus_ops;
-	ts->platform_data->dev = ts->dev;
+	init_completion(&ts->bl_ready);
 
 	if (ts->platform_data->init) {
-		retval = ts->platform_data->init(ts->platform_data, 1);
-		if (retval) {
+		if (ts->platform_data->init()) {
 			dev_dbg(ts->dev, "%s: Error, platform init failed!\n",
 				__func__);
-			retval = -EIO;
 			goto error_init;
 		}
 	}
@@ -791,28 +830,29 @@ int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
 	if (ts->irq <= 0) {
 		dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
 			__func__);
-			retval = -EIO;
 			goto error_init;
 	}
 
 	/* Create the input device and register it. */
 	input_device = input_allocate_device();
 	if (!input_device) {
-		retval = -ENOMEM;
 		dev_dbg(ts->dev, "%s: Error, failed to allocate input device\n",
 			__func__);
-			retval = -ENODEV;
 		goto error_input_allocate_device;
 	}
 
 	ts->input = input_device;
 	input_device->name = ts->platform_data->name;
+	snprintf(ts->phys, sizeof(ts->phys), "%s", dev_name(dev));
 	input_device->phys = ts->phys;
 	input_device->dev.parent = ts->dev;
 	ts->bus_type = bus_ops->dev->bus;
+	input_device->open = cyttsp_open;
+	input_device->close = cyttsp_close;
+	input_set_drvdata(input_device, ts);
 
 	cyttsp_init_tch_map(ts);
-	cyttsp_init_prv_trks(ts);
+	memset(ts->prv_trk, CY_NTCH, sizeof(ts->prv_trk));
 
 	__set_bit(EV_SYN, input_device->evbit);
 	__set_bit(EV_KEY, input_device->evbit);
@@ -824,61 +864,29 @@ int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
 		0, ts->platform_data->maxy, 0, 0);
 	input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
 		0, CY_MAXZ, 0, 0);
-	input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR,
-		0, CY_LARGE_TOOL_WIDTH, 0, 0);
-	input_set_abs_params(input_device, ABS_MT_TRACKING_ID,
-		0, CY_NUM_TRK_ID, 0, 0);
 
-	retval = input_register_device(input_device);
-	if (retval) {
+	if (input_register_device(input_device)) {
 		dev_dbg(ts->dev, "%s: Error, failed to register input device\n",
 			__func__);
-			retval = -ENODEV;
 		goto error_input_register_device;
 	}
 
-	retval = cyttsp_power_on(ts);
-
-	if (retval < 0) {
-		dev_dbg(ts->dev, "%s: Error, power on failed!\n", __func__);
-		retval = -ENODEV;
-		goto error_power_on;
-	}
-
-	handle = ts;
 	goto no_error;
 
-error_power_on:
-	free_irq(ts->irq, ts);
 error_input_register_device:
 	input_unregister_device(input_device);
 error_input_allocate_device:
-	if (ts->platform_data->init)
-		ts->platform_data->init(ts->platform_data, 0);
+	if (ts->platform_data->exit)
+		ts->platform_data->exit();
 error_init:
 	mutex_destroy(&ts->mutex);
 	kfree(ts);
 error_alloc_data:
-	handle = NULL;
 no_error:
-	return retval;
+	return ts;
 }
 EXPORT_SYMBOL_GPL(cyttsp_core_init);
 
-/* registered in driver struct */
-void cyttsp_core_release(void *handle)
-{
-	struct cyttsp *ts = handle;
-
-	mutex_destroy(&ts->mutex);
-	free_irq(ts->irq, ts);
-	input_unregister_device(ts->input);
-	if (ts->platform_data->init)
-		ts->platform_data->init(ts->platform_data, 0);
-	kfree(ts);
-}
-EXPORT_SYMBOL_GPL(cyttsp_core_release);
-
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
 MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
index 43fe438..58ab186 100644
--- a/drivers/input/touchscreen/cyttsp_core.h
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -30,6 +30,7 @@
 #define __CYTTSP_CORE_H__
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/input/cyttsp.h>
 
 #define CY_NUM_RETRY                4 /* max number of retries for read ops */
@@ -40,11 +41,9 @@ struct cyttsp_bus_ops {
 	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
 	s32 (*ext)(void *handle, void *values);
 	struct device *dev;
-	enum cyttsp_powerstate power_state;
 };
 
-int cyttsp_core_init(struct cyttsp_bus_ops *bus_ops,
-	struct device *dev, void *handle);
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *dev);
 
 void cyttsp_core_release(void *handle);
 #ifdef CONFIG_PM
diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
index 5280252..e942183 100644
--- a/include/linux/input/cyttsp.h
+++ b/include/linux/input/cyttsp.h
@@ -30,46 +30,35 @@
 #define CY_SPI_NAME "cyttsp-spi"
 #define CY_I2C_NAME "cyttsp-i2c"
 /* Active Power state scanning/processing refresh interval */
-#define CY_ACT_INTRVL_DFLT 0x00
+#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
 /* touch timeout for the Active power */
-#define CY_TCH_TMOUT_DFLT 0xFF
+#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
 /* Low Power state scanning/processing refresh interval */
-#define CY_LP_INTRVL_DFLT 0x0A
-/*
- * Active distance in pixels for a gesture to be reported
- * if set to 0, then all gesture movements are reported
- * Valid range is 0 - 15
- */
-#define CY_ACT_DIST_DFLT 8
-#define CY_ACT_DIST CY_ACT_DIST_DFLT
-
-enum cyttsp_gest {
-	CY_GEST_GRP_NONE = 0,
-	CY_GEST_GRP1 =	0x10,
-	CY_GEST_GRP2 = 0x20,
-	CY_GEST_GRP3 = 0x40,
-	CY_GEST_GRP4 = 0x80,
-};
+#define CY_LP_INTRVL_DFLT 0x0A /* ms */
+/* Active distance in pixels for a gesture to be reported */
+#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
 
 enum cyttsp_powerstate {
 	CY_IDLE_STATE,
 	CY_ACTIVE_STATE,
 	CY_LOW_PWR_STATE,
 	CY_SLEEP_STATE,
+	CY_BL_STATE,
+	CY_INVALID_STATE	/* always last in the list */
 };
 
 struct cyttsp_platform_data {
-	struct device *dev;
 	u32 maxx;
 	u32 maxy;
-	unsigned use_hndshk:1;
-	unsigned use_sleep:1;
-	u8 gest_set;	/* Active distance */
+	bool use_hndshk;
+	bool use_sleep;
+	u8 act_dist;	/* Active distance */
 	u8 act_intrvl;  /* Active refresh interval; ms */
 	u8 tch_tmout;   /* Active touch timeout; ms */
 	u8 lp_intrvl;   /* Low power refresh interval; ms */
 	int (*wakeup)(void);
-	int (*init)(struct cyttsp_platform_data *, int on_off);
+	int (*init)(void);
+	void (*exit)(void);
 	char *name;
 	s16 irq_gpio;
 	u8 *bl_keys;
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v2] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (5 preceding siblings ...)
  2010-12-04  2:06 ` [v2] touchscreen Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
@ 2010-12-04  2:06 ` Kevin McNeely
  2010-12-04  2:06 ` [v2] 3/3 spi: Cypress TTSP G3 MTDEV SPI " Kevin McNeely
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-12-04  2:06 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Luotao Fu, Henrik Rydberg, linux-input,
	linux-kernel

Amended version of Cypress TTSP Gen3 I2C Device Driver.
Provides i2c communications modules for the Cypress
TTSP Gen3 MTDEV Core Driver.
Amendments include changes recommended by reviewers of
initial version.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Makefile     |    4 ++--
 drivers/input/touchscreen/cyttsp_i2c.c |   20 ++++++++------------
 2 files changed, 10 insertions(+), 14 deletions(-)
 mode change 100644 => 100755 drivers/input/touchscreen/cyttsp_i2c.c

diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 9c142b8..88ee091 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,8 +16,8 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)	+= cyttsp_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)    += cyttsp_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
old mode 100644
new mode 100755
index cacfe4d..2a066d8b
--- a/drivers/input/touchscreen/cyttsp_i2c.c
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -87,17 +87,15 @@ static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
 	const struct i2c_device_id *id)
 {
 	struct cyttsp_i2c *ts;
-	int retval;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 		return -EIO;
 
 	/* allocate and clear memory */
 	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-	if (ts == NULL) {
+	if (!ts) {
 		dev_dbg(&client->dev, "%s: Error, kzalloc.\n", __func__);
-		retval = -ENOMEM;
-		goto error_alloc_data_failed;
+		return -ENOMEM;
 	}
 
 	/* register driver_data */
@@ -109,18 +107,16 @@ static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
 	ts->ops.dev = &client->dev;
 	ts->ops.dev->bus = &i2c_bus_type;
 
-	retval = cyttsp_core_init(&ts->ops, &client->dev, &ts->ttsp_client);
-	if (retval)
-		goto ttsp_core_err;
+	ts->ttsp_client = cyttsp_core_init(&ts->ops, &client->dev);
+	if (IS_ERR(ts->ttsp_client)) {
+		int retval = PTR_ERR(ts->ttsp_client);
+		kfree(ts);
+		return retval;
+	}
 
 	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
 
 	return 0;
-
-ttsp_core_err:
-	kfree(ts);
-error_alloc_data_failed:
-	return retval;
 }
 
 
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v2] 3/3 spi: Cypress TTSP G3 MTDEV SPI Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (6 preceding siblings ...)
  2010-12-04  2:06 ` [v2] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver Kevin McNeely
@ 2010-12-04  2:06 ` Kevin McNeely
  2010-12-29 19:17 ` [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-12-04  2:06 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Luotao Fu, Henrik Rydberg, linux-input,
	linux-kernel

Amended version of Cypress TTSP Gen3 SPI Device Driver.
Provides spi communications modules for the Cypress
TTSP Gen3 MTDEV Core Driver.
Amendments include changes recommended by reviewers of
initial version.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Makefile     |    4 +-
 drivers/input/touchscreen/cyttsp_spi.c |   84 +++++++++++++++++--------------
 2 files changed, 48 insertions(+), 40 deletions(-)

diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 89557f2..c52c0f5 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,8 +16,8 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)	+= cyttsp_core.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)	+= cyttsp_spi.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)    += cyttsp_spi.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
index 9f05de4..27b8347 100644
--- a/drivers/input/touchscreen/cyttsp_spi.c
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -33,7 +33,7 @@
 #define CY_SPI_WR_OP      0x00 /* r/~w */
 #define CY_SPI_RD_OP      0x01
 #define CY_SPI_CMD_BYTES  4
-#define CY_SPI_SYNC_BYTES 2
+#define CY_SPI_SYNC_BYTE  2
 #define CY_SPI_SYNC_ACK1  0x62 /* from protocol v.2 */
 #define CY_SPI_SYNC_ACK2  0x9D /* from protocol v.2 */
 #define CY_SPI_DATA_SIZE  128
@@ -77,19 +77,19 @@ static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts,
 			    u8 reg, u8 *buf, int length)
 {
 	struct spi_message msg;
-	struct spi_transfer xfer = { 0 };
+	struct spi_transfer xfer[2];
 	u8 *wr_buf = ts->wr_buf;
 	u8 *rd_buf = ts->rd_buf;
 	int retval;
-	int i;
 
 	if (length > CY_SPI_DATA_SIZE) {
 		dev_dbg(ts->ops.dev, "%s: length %d is too big.\n",
 			__func__, length);
 		return -EINVAL;
 	}
-	dev_dbg(ts->ops.dev, "%s: OP=%s length=%d\n", __func__,
-		   op == CY_SPI_RD_OP ? "Read" : "Write", length);
+
+	memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
+	memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
 
 	wr_buf[0] = 0x00; /* header byte 0 */
 	wr_buf[1] = 0xFF; /* header byte 1 */
@@ -98,35 +98,45 @@ static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts,
 	if (op == CY_SPI_WR_OP)
 		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
 
-	xfer.tx_buf = wr_buf;
-	xfer.rx_buf = rd_buf;
-	xfer.len = length + CY_SPI_CMD_BYTES;
-
-	if ((op == CY_SPI_RD_OP) && (xfer.len < 32))
-		xfer.len += 1;
-
+	memset((void *)xfer, 0, sizeof(xfer));
 	spi_message_init(&msg);
-	spi_message_add_tail(&xfer, &msg);
+	xfer[0].tx_buf = wr_buf;
+	xfer[0].rx_buf = rd_buf;
+	if (op == CY_SPI_WR_OP) {
+		xfer[0].len = length + CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+	} else if (op == CY_SPI_RD_OP) {
+		xfer[0].len = CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+
+		xfer[1].rx_buf = buf;
+		xfer[1].len = length;
+		spi_message_add_tail(&xfer[1], &msg);
+	}
+
 	retval = spi_sync_tmo(ts, &msg);
 	if (retval < 0) {
-		dev_dbg(ts->ops.dev, "%s: spi_sync_tmo() error %d\n",
-			__func__, retval);
+		dev_dbg(ts->ops.dev, "%s: spi sync error %d, len=%d, op=%d\n",
+			__func__, retval, xfer[1].len, op);
 		retval = 0;
 	}
+
 	if (op == CY_SPI_RD_OP) {
-		for (i = 0; i < (length + CY_SPI_CMD_BYTES - 1); i++) {
-			if ((rd_buf[i] != CY_SPI_SYNC_ACK1) ||
-				(rd_buf[i + 1] != CY_SPI_SYNC_ACK2)) {
-				continue;
-			}
-			if (i <= (CY_SPI_CMD_BYTES - 1)) {
-				memcpy(buf, (rd_buf + i + CY_SPI_SYNC_BYTES),
-					length);
-				return 0;
-			}
+		if ((rd_buf[CY_SPI_SYNC_BYTE] == CY_SPI_SYNC_ACK1) &&
+			(rd_buf[CY_SPI_SYNC_BYTE+1] == CY_SPI_SYNC_ACK2))
+			retval = 0;
+		else {
+			int i;
+			for (i = 0; i < (CY_SPI_CMD_BYTES); i++)
+				dev_dbg(ts->ops.dev,
+					"%s: test rd_buf[%d]:0x%02x\n",
+					__func__, i, rd_buf[i]);
+			for (i = 0; i < (length); i++)
+				dev_dbg(ts->ops.dev,
+					"%s: test buf[%d]:0x%02x\n",
+					__func__, i, buf[i]);
+			retval = 1;
 		}
-		dev_dbg(ts->ops.dev, "%s: byte sync error\n", __func__);
-		retval = 1;
 	}
 	return retval;
 }
@@ -223,11 +233,11 @@ static int __devinit cyttsp_spi_probe(struct spi_device *spi)
 	}
 
 	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
-	if (ts == NULL) {
+	if (!ts) {
 		dev_dbg(&spi->dev, "%s: Error, kzalloc\n", __func__);
-		retval = -ENOMEM;
-		goto error_alloc_data_failed;
+		return -ENOMEM;
 	}
+
 	ts->spi_client = spi;
 	dev_set_drvdata(&spi->dev, ts);
 	ts->ops.write = ttsp_spi_write_block_data;
@@ -235,18 +245,16 @@ static int __devinit cyttsp_spi_probe(struct spi_device *spi)
 	ts->ops.ext = ttsp_spi_tch_ext;
 	ts->ops.dev = &spi->dev;
 
-	retval = cyttsp_core_init(&ts->ops, &spi->dev,  &ts->ttsp_client);
-	if (retval)
-		goto ttsp_core_err;
+	ts->ttsp_client = cyttsp_core_init(&ts->ops, &spi->dev);
+	if (IS_ERR(ts->ttsp_client)) {
+		int retval = PTR_ERR(ts->ttsp_client);
+		kfree(ts);
+		return retval;
+	}
 
 	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
 
 	return 0;
-
-ttsp_core_err:
-	kfree(ts);
-error_alloc_data_failed:
-	return retval;
 }
 
 static int __devexit cyttsp_spi_remove(struct spi_device *spi)
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v2] touchscreen Cypress TTSP G3 MTDEV Core Driver
  2010-12-04  2:06 ` [v2] touchscreen Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
@ 2010-12-05  9:11   ` Henrik Rydberg
  0 siblings, 0 replies; 70+ messages in thread
From: Henrik Rydberg @ 2010-12-05  9:11 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Luotao Fu, linux-input, linux-kernel

On 12/04/2010 03:06 AM, Kevin McNeely wrote:

> Amended version of Cypress TTSP Gen3 Core Driver.
> Core Driver includes platform data definition file,
> core driver definition file, and core touchscreen
> touch handling of device data. Generates
> multi-touch input events.
> Amendments include changes recommended by reviewers
> of initial version.  Kconfig is for I2C and SPI modules
> including the core.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>


Hi Kevin, please send full patches rather than diffs next round.

> @@ -87,8 +89,8 @@
>  
>  /* Touch structure */
>  struct cyttsp_touch {
> -	u16 x __attribute__ ((packed));
> -	u16 y __attribute__ ((packed));
> +	u8 x[2];
> +	u8 y[2];
>  	u8 z;
>  };


Any particular reason why this could not stay as u16?


> @@ -500,35 +492,27 @@ static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
>  	 * is missing from the current event
>  	 */
>  	for (id = 0; id < CY_NUM_TRK_ID; id++) {
> -		if (t->cur_trk[id].tch) {
> +		if (cur_trk[id].tch) {


Here tch is used as a bool, and yet the values CY_NTCH and CY_TCH exist, which
is inconsistent. Removing the defines reduces some lines and makes the code
easier to read.

>  			/* put active current track data */
>  			input_report_abs(ts->input,
> -				ABS_MT_TRACKING_ID, id);
> -			input_report_abs(ts->input,
> -				ABS_MT_WIDTH_MAJOR, t->cur_trk[id].w);
> +				ABS_MT_POSITION_X, cur_trk[id].x);
>  			input_report_abs(ts->input,
> -				ABS_MT_POSITION_X, t->cur_trk[id].x);
> +				ABS_MT_POSITION_Y, cur_trk[id].y);
>  			input_report_abs(ts->input,
> -				ABS_MT_POSITION_Y, t->cur_trk[id].y);
> -			input_report_abs(ts->input,
> -				ABS_MT_TOUCH_MAJOR, t->cur_trk[id].z);
> +				ABS_MT_TOUCH_MAJOR, cur_trk[id].z);
>  			input_mt_sync(ts->input);
>  
> -			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d\n",
> -				__func__,
> -				t->cur_trk[id].x,
> -				t->cur_trk[id].y,
> -				t->cur_trk[id].z);
> -			/* save current track data into previous track data */
> -			ts->prv_trk[id] = t->cur_trk[id];
> +			dev_dbg(ts->dev, "%s: MT% 2d: X=%d Y=%d Z=%d\n",
> +				__func__, id,
> +				cur_trk[id].x,
> +				cur_trk[id].y,
> +				cur_trk[id].z);
> +			/* save current touch xy_data as previous track data */
> +			ts->prv_trk[id] = cur_trk[id];

>  			cnt++;
>  		} else if (ts->prv_trk[id].tch) {
>  			/* put lift-off previous track data */
>  			input_report_abs(ts->input,
> -				ABS_MT_TRACKING_ID, id);
> -			input_report_abs(ts->input,
> -				ABS_MT_WIDTH_MAJOR, ts->prv_trk[id].w);
> -			input_report_abs(ts->input,
>  				ABS_MT_POSITION_X, ts->prv_trk[id].x);
>  			input_report_abs(ts->input,
>  				ABS_MT_POSITION_Y, ts->prv_trk[id].y);
> @@ -536,11 +520,12 @@ static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
>  				ABS_MT_TOUCH_MAJOR, CY_NTCH);
>  			input_mt_sync(ts->input);
>  
> -			dev_dbg(ts->dev, "%s: MT1: X=%d Y=%d Z=%d lift-off\n",
> -				__func__,
> +			dev_dbg(ts->dev, "%s: MT% 2d: X=%d Y=%d Z=%d liftoff\n",
> +				__func__, id,
>  				ts->prv_trk[id].x,
>  				ts->prv_trk[id].y,
>  				CY_NTCH);
> +			/* clear previous touch indication */
>  			ts->prv_trk[id].tch = CY_NTCH;
>  			cnt++;
>  		}


There seems to be no reason to keep the debug code and setting of prk_trk[] in
different branches. Please simplify.

> @@ -551,27 +536,21 @@ static void handle_multi_touch(struct cyttsp_track_data *t, struct cyttsp *ts)
>  		input_sync(ts->input);
>  }
>  
> -static void cyttsp_get_xydata(struct cyttsp *ts,
> -	struct cyttsp_track_data *t,
> -	u8 id, u8 w, u16 x, u16 y, u8 z)
> -{
> -	struct cyttsp_trk *trk;
> -
> -	trk = &(t->cur_trk[id]);
> -	trk->tch = CY_TCH;
> -	trk->w = w;
> -	trk->x = x;
> -	trk->y = y;
> -	trk->z = z;
> -}
> -
> +/* read xy_data for all current touches */
>  static int cyttsp_xy_worker(struct cyttsp *ts)
>  {
>  	u8 cur_tch = 0;
>  	u8 tch;
> -	struct cyttsp_track_data trk;
> +	u8 id;
> +	u8 *x;
> +	u8 *y;
> +	u8 z;


Please move these to the loop, if the loop is really needed.

> +	struct cyttsp_trk cur_trk[CY_NUM_TRK_ID];
>  
> -	/* get event data from CYTTSP device */
> +	/* Get event data from CYTTSP device.
> +	 * The event data includes all data
> +	 * for all active touches.
> +	 */
>  	if (ttsp_read_block_data(ts,
>  		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
>  		return 0;
> @@ -585,9 +564,11 @@ static int cyttsp_xy_worker(struct cyttsp *ts)
>  		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
>  			return 0;
>  
> +	/* determine number of currently active touches */
>  	cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
>  
> -	if (ts->bus_ops->power_state == CY_IDLE_STATE)
> +	/* check for any error conditions */
> +	if (ts->power_state == CY_IDLE_STATE)
>  		return 0;
>  	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
>  		return -1;
> @@ -605,44 +586,70 @@ static int cyttsp_xy_worker(struct cyttsp *ts)
>  		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
>  	}
>  
> -	/* process the touches */
> -	cyttsp_init_cur_trks(&trk);
> +	/* clear current touch tracking structures */
> +	memset(cur_trk, CY_NTCH, sizeof(cur_trk));
>  
> +	/* extract xy_data for all currently reported touches */
>  	for (tch = 0; tch < cur_tch; tch++) {
> -		cyttsp_get_xydata(ts, &trk,
> -			tch & 0x01 ?
> +		id = tch & 0x01 ?
>  			(*(ts->tch_map[tch].id) & 0x0F) :
> -			(*(ts->tch_map[tch].id) & 0xF0) >> 4,
> -			CY_SMALL_TOOL_WIDTH,
> -			be16_to_cpu((ts->tch_map[tch].tch)->x),
> -			be16_to_cpu((ts->tch_map[tch].tch)->y),
> -			(ts->tch_map[tch].tch)->z);
> +			(*(ts->tch_map[tch].id) & 0xF0) >> 4;
> +		x = (u8 *)&((ts->tch_map[tch].tch)->x);
> +		y = (u8 *)&((ts->tch_map[tch].tch)->y);
> +		z = (ts->tch_map[tch].tch)->z;
> +		cur_trk[id].tch = CY_TCH;
> +		cur_trk[id].x = ((u16)x[0] << 8) + x[1];
> +		cur_trk[id].y = ((u16)y[0] << 8) + y[1];
> +		cur_trk[id].z = z;
>  	}
>  
> -	handle_multi_touch(&trk, ts);
> +	/* provide input event signaling for each active touch */
> +	handle_multi_touch(cur_trk, ts);
>  
>  	return 0;
>  }


This change does not seem to actually simplify much. How likely is it that this
driver will support more than two fingers and still be using the type A
protocol? A function setting up cur_trk[] explicitly from the device data would
be cleaner.

Thanks,
Henrik


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (7 preceding siblings ...)
  2010-12-04  2:06 ` [v2] 3/3 spi: Cypress TTSP G3 MTDEV SPI " Kevin McNeely
@ 2010-12-29 19:17 ` Kevin McNeely
  2010-12-30  6:04   ` Shubhrajyoti Datta
                     ` (2 more replies)
  2010-12-29 19:17 ` [v3 2/3] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver Kevin McNeely
                   ` (4 subsequent siblings)
  13 siblings, 3 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-12-29 19:17 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Henrik Rydberg, Samuel Ortiz, Eric Miao, Mike Frysinger,
	Alan Cox, linux-input, linux-kernel

Cypress TTSP Gen3 Core Driver.
Core Driver includes platform data definition file,
core driver definition file, and core touchscreen
touch handling of device data. Generates
multi-touch input events.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
Changes since v2:
- Simplified Protocol A
- Modified pointed out driver writing style

 drivers/input/touchscreen/Kconfig       |    5 +
 drivers/input/touchscreen/Makefile      |    1 +
 drivers/input/touchscreen/cyttsp_core.c |  808 +++++++++++++++++++++++++++++++
 drivers/input/touchscreen/cyttsp_core.h |   55 +++
 include/linux/input/cyttsp.h            |   68 +++
 5 files changed, 937 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_core.c
 create mode 100644 drivers/input/touchscreen/cyttsp_core.h
 create mode 100644 include/linux/input/cyttsp.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 06ea8da..7d886bc 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
 	  To compile this driver as a module, choose M here: the
 	  module will be called cy8ctmg110_ts.
 
+config TOUCHSCREEN_CYTTSP_CORE
+	bool "Cypress TTSP touchscreen core"
+	help
+	  Always activated for Cypress TTSP touchscreen
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 7cc1b4f..b6f1ba8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 0000000..21a342f
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,808 @@
+/*
+ * Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Bootloader File 0 offset */
+#define CY_BL_FILE0       0x00
+/* Bootloader command directive */
+#define CY_BL_CMD         0xFF
+/* Bootloader Exit and Verify Checksum command */
+#define CY_BL_EXIT        0xA5
+/* Bootloader number of command keys */
+#define CY_NUM_BL_KEYS    8
+/* Bootloader default command keys */
+#define CY_BL_KEY0 0
+#define CY_BL_KEY1 1
+#define CY_BL_KEY2 2
+#define CY_BL_KEY3 3
+#define CY_BL_KEY4 4
+#define CY_BL_KEY5 5
+#define CY_BL_KEY6 6
+#define CY_BL_KEY7 7
+
+/* helpers */
+#define GET_NUM_TOUCHES(x)          ((x) & 0x0F)
+#define IS_LARGE_AREA(x)            (((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x)               ((x) & 0x20)
+#define IS_VALID_APP(x)             ((x) & 0x01)
+#define IS_OPERATIONAL_ERR(x)       ((x) & 0x3F)
+#define GET_HSTMODE(reg)            ((reg & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)     ((reg & 0x10) >> 4)
+
+#define CY_REG_BASE                 0x00
+#define CY_REG_ACT_DIST             0x1E
+#define CY_REG_ACT_INTRVL           0x1D
+#define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
+#define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
+#define CY_MAXZ                     255
+#define CY_DELAY_DFLT               20 /* ms */
+#define CY_DELAY_MAX                (500/CY_DELAY_DFLT) /* half second */
+#define CY_ACT_DIST_DFLT            0xF8
+#define CY_HNDSHK_BIT               0x80
+/* device mode bits */
+#define CY_OPERATE_MODE             0x00
+#define CY_SYSINFO_MODE             0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE          0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE          0x02
+#define CY_LOW_POWER_MODE           0x04
+
+/* TrueTouch Standard Product Gen3 interface definition */
+struct cyttsp_xydata {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	u8 tch1_xhi;
+	u8 tch1_xlo;
+	u8 tch1_yhi;
+	u8 tch1_ylo;
+	u8 tch1_z;
+	u8 unused;
+	u8 tch2_xhi;
+	u8 tch2_xlo;
+	u8 tch2_yhi;
+	u8 tch2_ylo;
+	u8 tch2_z;
+	u8 unused_grp[13];
+	u8 tt_undef[3];
+	u8 act_dist;
+	u8 tt_reserved;
+};
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[5];
+	u8 scn_typ;
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+struct cyttsp_tch {
+	u16 x;
+	u16 y;
+	u8 z;
+};
+
+struct cyttsp {
+	struct device *dev;
+	int irq;
+	struct input_dev *input;
+	struct mutex mutex;
+	char phys[32];
+	const struct bus_type *bus_type;
+	const struct cyttsp_platform_data *platform_data;
+	struct cyttsp_bus_ops *bus_ops;
+	struct cyttsp_xydata xy_data;
+	struct cyttsp_bootloader_data bl_data;
+	struct cyttsp_sysinfo_data sysinfo_data;
+	struct completion bl_ready;
+	enum cyttsp_powerstate power_state;
+};
+
+static const u8 bl_command[] = {
+	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
+	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
+	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
+	CY_BL_KEY6, CY_BL_KEY7
+};
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int retval;
+	int tries;
+
+	if (!buf || !length)
+		return -EIO;
+
+	for (tries = 0, retval = -1;
+		tries < CY_NUM_RETRY && (retval < 0);
+		tries++)
+		retval = ts->bus_ops->read(ts->bus_ops, command, length, buf);
+
+	return retval;
+}
+
+static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int retval;
+	if (!buf || !length)
+		return -EIO;
+
+	retval = ts->bus_ops->write(ts->bus_ops, command, length, buf);
+
+	return retval;
+}
+
+static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
+{
+	int retval;
+
+	if (!buf)
+		return -EIO;
+
+	retval = ts->bus_ops->ext(ts->bus_ops, buf);
+
+	return retval;
+}
+
+static int cyttsp_load_bl_regs(struct cyttsp *ts)
+{
+	int retval;
+
+	memset(&(ts->bl_data), 0, sizeof(struct cyttsp_bootloader_data));
+
+	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
+		sizeof(ts->bl_data), &(ts->bl_data));
+
+	return retval;
+}
+
+static int cyttsp_bl_app_valid(struct cyttsp *ts)
+{
+	int retval;
+
+	retval = cyttsp_load_bl_regs(ts);
+
+	if (retval < 0)
+		return -ENODEV;
+
+	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) {
+		if (IS_VALID_APP(ts->bl_data.bl_status)) {
+			dev_dbg(ts->dev, "%s: App found; normal boot\n",
+				__func__);
+			return 0;
+		} else {
+			dev_dbg(ts->dev, "%s: NO APP; load firmware!!\n",
+				__func__);
+			return -ENODEV;
+		}
+	} else if (GET_HSTMODE(ts->bl_data.bl_file) == CY_OPERATE_MODE) {
+		if (!(IS_OPERATIONAL_ERR(ts->bl_data.bl_status))) {
+			dev_dbg(ts->dev, "%s: Operational\n",
+				__func__);
+			return 1;
+		} else {
+			dev_dbg(ts->dev, "%s: Operational failure\n",
+				__func__);
+			return -ENODEV;
+		}
+	} else {
+		dev_dbg(ts->dev, "%s: Non-Operational failure\n",
+			__func__);
+			return -ENODEV;
+	}
+
+}
+
+static int cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries;
+	u8 bl_cmd[sizeof(bl_command)];
+
+	memcpy(bl_cmd, bl_command, sizeof(bl_command));
+	if (ts->platform_data->bl_keys)
+		memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
+			ts->platform_data->bl_keys, sizeof(bl_command));
+
+	dev_dbg(ts->dev,
+		"%s: bl_cmd= "
+		"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
+		__func__, bl_cmd[0], bl_cmd[1], bl_cmd[2],
+		bl_cmd[3], bl_cmd[4], bl_cmd[5], bl_cmd[6],
+		bl_cmd[7], bl_cmd[8], bl_cmd[9], bl_cmd[10]);
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE,
+		sizeof(bl_cmd), (void *)bl_cmd);
+	if (retval < 0)
+		return retval;
+
+	/* wait for TTSP Device to complete switch to Operational mode */
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = cyttsp_load_bl_regs(ts);
+	} while (!((retval == 0) &&
+		!GET_BOOTLOADERMODE(ts->bl_data.bl_status)) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check bl ready tries=%d ret=%d stat=%02X\n",
+		__func__, tries, retval, ts->bl_data.bl_status);
+
+	if (retval < 0)
+		return retval;
+	else if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
+		return -ENODEV;
+	else
+		return 0;
+}
+
+static int cyttsp_set_operational_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries;
+	u8 cmd = CY_OPERATE_MODE;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+
+	if (retval < 0)
+		return retval;
+
+	/* wait for TTSP Device to complete switch to Operational mode */
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = ttsp_read_block_data(ts, CY_REG_BASE,
+			sizeof(ts->xy_data), &(ts->xy_data));
+	} while (!((retval == 0) &&
+		(ts->xy_data.act_dist == CY_ACT_DIST_DFLT)) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check op ready tries=%d ret=%d dist=%02X\n",
+		__func__, tries, retval, ts->xy_data.act_dist);
+
+	return retval;
+}
+
+static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries;
+	u8 cmd = CY_SYSINFO_MODE;
+
+	memset(&(ts->sysinfo_data), 0, sizeof(struct cyttsp_sysinfo_data));
+
+	/* switch to sysinfo mode */
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (retval < 0)
+		return retval;
+
+	/* read sysinfo registers */
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = ttsp_read_block_data(ts, CY_REG_BASE,
+			sizeof(ts->sysinfo_data), &(ts->sysinfo_data));
+	} while (!((retval == 0) &&
+		!((ts->sysinfo_data.tts_verh == 0) &&
+		(ts->sysinfo_data.tts_verl == 0))) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check sysinfo ready tries=%d ret=%d\n",
+		__func__, tries, retval);
+
+	dev_info(ts->dev, "%s: tv=%02X%02X ai=0x%02X%02X "
+		"av=0x%02X%02X ci=0x%02X%02X%02X\n", "cyttsp",
+		ts->sysinfo_data.tts_verh, ts->sysinfo_data.tts_verl,
+		ts->sysinfo_data.app_idh, ts->sysinfo_data.app_idl,
+		ts->sysinfo_data.app_verh, ts->sysinfo_data.app_verl,
+		ts->sysinfo_data.cid[0], ts->sysinfo_data.cid[1],
+		ts->sysinfo_data.cid[2]);
+
+	return retval;
+}
+
+static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	if (ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT ||
+		ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT ||
+		ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT) {
+
+		u8 intrvl_ray[3];
+
+		intrvl_ray[0] = ts->platform_data->act_intrvl;
+		intrvl_ray[1] = ts->platform_data->tch_tmout;
+		intrvl_ray[2] = ts->platform_data->lp_intrvl;
+
+		/* set intrvl registers */
+		retval = ttsp_write_block_data(ts,
+				CY_REG_ACT_INTRVL,
+				sizeof(intrvl_ray), intrvl_ray);
+
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return retval;
+}
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+	int retval;
+	u8 cmd = CY_SOFT_RESET_MODE;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (retval < 0)
+		return retval;
+
+	/* wait for interrupt to set ready completion */
+	INIT_COMPLETION(ts->bl_ready);
+
+	retval = wait_for_completion_interruptible_timeout(&ts->bl_ready,
+		msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
+
+	if (retval > 0)
+		retval = 0;
+
+	return retval;
+}
+
+static int cyttsp_act_dist_setup(struct cyttsp *ts)
+{
+	int retval;
+	u8 act_dist_setup;
+
+	/* Init gesture; active distance setup */
+	act_dist_setup = ts->platform_data->act_dist;
+	retval = ttsp_write_block_data(ts, CY_REG_ACT_DIST,
+		sizeof(act_dist_setup), &act_dist_setup);
+
+	return retval;
+}
+
+static int cyttsp_hndshk(struct cyttsp *ts, u8 hst_mode)
+{
+	int retval;
+	u8 cmd;
+
+	cmd = hst_mode & CY_HNDSHK_BIT ?
+		hst_mode & ~CY_HNDSHK_BIT :
+		hst_mode | CY_HNDSHK_BIT;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE,
+		sizeof(cmd), (u8 *)&cmd);
+
+	return retval;
+}
+
+/* process current touches */
+static int cyttsp_xy_worker(struct cyttsp *ts)
+{
+	u8 num_cur_tch = 0;
+	u16 x;
+	u16 y;
+	u8 z;
+
+	/* Get touch data from CYTTSP device */
+	if (ttsp_read_block_data(ts,
+		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
+		return 0;
+
+	/* touch extension handling */
+	if (ttsp_tch_ext(ts, &ts->xy_data))
+		return 0;
+
+	/* provide flow control handshake */
+	if (ts->platform_data->use_hndshk)
+		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
+			return 0;
+
+	/* determine number of currently active touches */
+	num_cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
+
+	/* check for any error conditions */
+	if (ts->power_state == CY_IDLE_STATE)
+		return 0;
+	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
+		return -1;
+	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
+		/* terminate all active tracks */
+		num_cur_tch = 0;
+		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
+	} else if (num_cur_tch > 2) {
+		/* terminate all active tracks */
+		num_cur_tch = 0;
+		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
+	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
+		/* terminate all active tracks */
+		num_cur_tch = 0;
+		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
+	}
+
+	/* send touches */
+	if (!num_cur_tch)
+		/* terminate previous active touch */
+		input_mt_sync(ts->input);
+
+	if (num_cur_tch) {
+		/* send touch 1 */
+		/*
+		 * If there is only one current active touch,
+		 * it will be reported in the touch 1 regardless
+		 * if it was reported in the touch 2 previously
+		 */
+		x = (ts->xy_data.tch1_xhi << 8) + ts->xy_data.tch1_xlo;
+		y = (ts->xy_data.tch1_yhi << 8) + ts->xy_data.tch1_ylo;
+		z = ts->xy_data.tch1_z;
+		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
+		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
+		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
+		input_mt_sync(ts->input);
+	}
+
+	if (num_cur_tch > 1) {
+		/* send touch 2 */
+		x = (ts->xy_data.tch2_xhi << 8) + ts->xy_data.tch2_xlo;
+		y = (ts->xy_data.tch2_yhi << 8) + ts->xy_data.tch2_ylo;
+		z = ts->xy_data.tch2_z;
+		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
+		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
+		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
+		input_mt_sync(ts->input);
+	}
+
+	input_sync(ts->input);
+
+	return 0;
+}
+
+static void cyttsp_pr_state(struct cyttsp *ts)
+{
+	static char *cyttsp_powerstate_string[] = {
+		"IDLE",
+		"ACTIVE",
+		"LOW_PWR",
+		"SLEEP",
+		"BOOTLOADER",
+		"INVALID"
+	};
+
+	dev_info(ts->dev, "%s: %s\n", __func__,
+		ts->power_state < CY_INVALID_STATE ?
+		cyttsp_powerstate_string[ts->power_state] :
+		"INVALID");
+}
+
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = handle;
+	int retval;
+
+	if (ts->power_state == CY_BL_STATE)
+		complete(&ts->bl_ready);
+	else {
+		/* process the touches */
+		retval = cyttsp_xy_worker(ts);
+
+		if (retval < 0) {
+			/*
+			 * TTSP device has reset back to bootloader mode.
+			 * Restore to operational mode.
+			 */
+			retval = cyttsp_exit_bl_mode(ts);
+			if (retval)
+				ts->power_state = CY_IDLE_STATE;
+			else
+				ts->power_state = CY_ACTIVE_STATE;
+			cyttsp_pr_state(ts);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	if (!ts)
+		return -ENOMEM;
+
+	ts->power_state = CY_BL_STATE;
+
+	/* enable interrupts */
+	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		ts->platform_data->name, ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_soft_reset(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_bl_app_valid(ts);
+	if (retval < 0)
+		goto bypass;
+	else if (retval > 0)
+		goto no_bl_bypass;
+
+	retval = cyttsp_exit_bl_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	ts->power_state = CY_IDLE_STATE;
+
+no_bl_bypass:
+	retval = cyttsp_set_sysinfo_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_set_sysinfo_regs(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_set_operational_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	/* init active distance */
+	retval = cyttsp_act_dist_setup(ts);
+	if (retval < 0)
+		goto bypass;
+
+	ts->power_state = CY_ACTIVE_STATE;
+	retval = 0;
+
+bypass:
+	cyttsp_pr_state(ts);
+	return retval;
+}
+
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle)
+{
+	struct cyttsp *ts = handle;
+	int retval = 0;
+	struct cyttsp_xydata xydata;
+
+	if (ts->platform_data->use_sleep && (ts->power_state !=
+		CY_ACTIVE_STATE)) {
+		if (ts->platform_data->wakeup) {
+			retval = ts->platform_data->wakeup();
+			if (retval < 0)
+				dev_dbg(ts->dev, "%s: Error, wakeup failed!\n",
+					__func__);
+		} else {
+			dev_dbg(ts->dev, "%s: Error, wakeup not implemented "
+				"(check board file).\n", __func__);
+			retval = -ENOSYS;
+		}
+		if (!(retval < 0)) {
+			retval = ttsp_read_block_data(ts, CY_REG_BASE,
+				sizeof(xydata), &xydata);
+			if (!(retval < 0) && !GET_HSTMODE(xydata.hst_mode))
+				ts->power_state = CY_ACTIVE_STATE;
+		}
+	}
+	dev_dbg(ts->dev, "%s: Wake Up %s\n", __func__,
+		(retval < 0) ? "FAIL" : "PASS");
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cyttsp_resume);
+
+int cyttsp_suspend(void *handle)
+{
+	struct cyttsp *ts = handle;
+	u8 sleep_mode = 0;
+	int retval = 0;
+
+	if (ts->platform_data->use_sleep &&
+		(ts->power_state == CY_ACTIVE_STATE)) {
+		sleep_mode = CY_DEEP_SLEEP_MODE;
+		retval = ttsp_write_block_data(ts,
+			CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
+		if (!(retval < 0))
+			ts->power_state = CY_SLEEP_STATE;
+	}
+	dev_dbg(ts->dev, "%s: Sleep Power state is %s\n", __func__,
+		(ts->power_state == CY_ACTIVE_STATE) ?
+		"ACTIVE" :
+		((ts->power_state == CY_SLEEP_STATE) ?
+		"SLEEP" : "LOW POWER"));
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cyttsp_suspend);
+#endif
+
+static int cyttsp_open(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	return cyttsp_power_on(ts);
+}
+
+void cyttsp_core_release(void *handle)
+{
+	struct cyttsp *ts = handle;
+
+	if (ts) {
+		mutex_destroy(&ts->mutex);
+		free_irq(ts->irq, ts);
+		input_unregister_device(ts->input);
+		if (ts->platform_data->exit)
+			ts->platform_data->exit();
+		kfree(ts);
+	}
+}
+EXPORT_SYMBOL_GPL(cyttsp_core_release);
+
+static void cyttsp_close(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	free_irq(ts->irq, ts);
+}
+
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *dev)
+{
+	struct input_dev *input_device;
+
+	struct cyttsp *ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+
+	if (!ts) {
+		dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
+		goto error_alloc_data;
+	}
+
+	if (dev == NULL || bus_ops == NULL) {
+		kfree(ts);
+		goto error_alloc_data;
+	}
+
+	mutex_init(&ts->mutex);
+	ts->dev = dev;
+	ts->platform_data = dev->platform_data;
+	ts->bus_ops = bus_ops;
+	init_completion(&ts->bl_ready);
+
+	if (ts->platform_data->init) {
+		if (ts->platform_data->init()) {
+			dev_dbg(ts->dev, "%s: Error, platform init failed!\n",
+				__func__);
+			goto error_init;
+		}
+	}
+
+	ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
+	if (ts->irq <= 0) {
+		dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
+			__func__);
+			goto error_init;
+	}
+
+	/* Create the input device and register it. */
+	input_device = input_allocate_device();
+	if (!input_device) {
+		dev_dbg(ts->dev, "%s: Error, failed to allocate input device\n",
+			__func__);
+		goto error_input_allocate_device;
+	}
+
+	ts->input = input_device;
+	input_device->name = ts->platform_data->name;
+	snprintf(ts->phys, sizeof(ts->phys), "%s", dev_name(dev));
+	input_device->phys = ts->phys;
+	input_device->dev.parent = ts->dev;
+	ts->bus_type = bus_ops->dev->bus;
+	input_device->open = cyttsp_open;
+	input_device->close = cyttsp_close;
+	input_set_drvdata(input_device, ts);
+
+	__set_bit(EV_SYN, input_device->evbit);
+	__set_bit(EV_KEY, input_device->evbit);
+	__set_bit(EV_ABS, input_device->evbit);
+
+	input_set_abs_params(input_device, ABS_MT_POSITION_X,
+		0, ts->platform_data->maxx, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_POSITION_Y,
+		0, ts->platform_data->maxy, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
+		0, CY_MAXZ, 0, 0);
+
+	if (input_register_device(input_device)) {
+		dev_dbg(ts->dev, "%s: Error, failed to register input device\n",
+			__func__);
+		goto error_input_register_device;
+	}
+
+	goto no_error;
+
+error_input_register_device:
+	input_unregister_device(input_device);
+error_input_allocate_device:
+	if (ts->platform_data->exit)
+		ts->platform_data->exit();
+error_init:
+	mutex_destroy(&ts->mutex);
+	kfree(ts);
+error_alloc_data:
+no_error:
+	return ts;
+}
+EXPORT_SYMBOL_GPL(cyttsp_core_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
+MODULE_AUTHOR("Cypress");
+
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
new file mode 100644
index 0000000..b6fa22a
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -0,0 +1,55 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+
+#ifndef __CYTTSP_CORE_H__
+#define __CYTTSP_CORE_H__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/input/cyttsp.h>
+
+#define CY_NUM_RETRY                4 /* max number of retries for read ops */
+
+
+struct cyttsp_bus_ops {
+	s32 (*write)(void *handle, u8 addr, u8 length, const void *values);
+	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
+	s32 (*ext)(void *handle, void *values);
+	struct device *dev;
+};
+
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *dev);
+
+void cyttsp_core_release(void *handle);
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle);
+int cyttsp_suspend(void *handle);
+#endif
+
+#endif /* __CYTTSP_CORE_H__ */
diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
new file mode 100644
index 0000000..c3959ce
--- /dev/null
+++ b/include/linux/input/cyttsp.h
@@ -0,0 +1,68 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+#ifndef _CYTTSP_H_
+#define _CYTTSP_H_
+
+#define CY_SPI_NAME "cyttsp-spi"
+#define CY_I2C_NAME "cyttsp-i2c"
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT 0x0A /* ms */
+/* Active distance in pixels for a gesture to be reported */
+#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
+
+enum cyttsp_powerstate {
+	CY_IDLE_STATE,
+	CY_ACTIVE_STATE,
+	CY_LOW_PWR_STATE,
+	CY_SLEEP_STATE,
+	CY_BL_STATE,
+	CY_INVALID_STATE	/* always last in the list */
+};
+
+struct cyttsp_platform_data {
+	u32 maxx;
+	u32 maxy;
+	bool use_hndshk;
+	bool use_sleep;
+	u8 act_dist;	/* Active distance */
+	u8 act_intrvl;  /* Active refresh interval; ms */
+	u8 tch_tmout;   /* Active touch timeout; ms */
+	u8 lp_intrvl;   /* Low power refresh interval; ms */
+	int (*wakeup)(void);
+	int (*init)(void);
+	void (*exit)(void);
+	char *name;
+	s16 irq_gpio;
+	u8 *bl_keys;
+};
+
+#endif /* _CYTTSP_H_ */
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v3 2/3] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (8 preceding siblings ...)
  2010-12-29 19:17 ` [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
@ 2010-12-29 19:17 ` Kevin McNeely
  2011-01-04  1:45   ` Hong Liu
  2010-12-29 19:17 ` [v3 3/3] 3/3 spi: Cypress TTSP G3 MTDEV SPI " Kevin McNeely
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2010-12-29 19:17 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Mike Frysinger, Henrik Rydberg,
	Alan Cox, linux-input, linux-kernel

Cypress TTSP Gen3 I2C Device Driver.
Provides i2c communications modules for the
Cypress TTSP Gen3 MTDEV Core Driver.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
Changes since v2:
- Fixed first line of multi-line comments to follow style guide

 drivers/input/touchscreen/Kconfig      |   12 ++
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/cyttsp_i2c.c |  183 ++++++++++++++++++++++++++++++++
 3 files changed, 196 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_i2c.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 7d886bc..e1a37f5 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -129,6 +129,18 @@ config TOUCHSCREEN_CYTTSP_CORE
 	help
 	  Always activated for Cypress TTSP touchscreen
 
+config TOUCHSCREEN_CYTTSP_I2C
+	tristate "Cypress TTSP i2c touchscreen"
+	depends on I2C && TOUCHSCREEN_CYTTSP_CORE
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system with an I2C interface.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp-i2c.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index b6f1ba8..88ee091 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)    += cyttsp_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100644
index 0000000..a83efd3
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -0,0 +1,183 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#define CY_I2C_DATA_SIZE  128
+
+struct cyttsp_i2c {
+	struct cyttsp_bus_ops ops;
+	struct i2c_client *client;
+	void *ttsp_client;
+	u8 wr_buf[CY_I2C_DATA_SIZE];
+};
+
+static s32 ttsp_i2c_read_block_data(void *handle, u8 addr,
+	u8 length, void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval = 0;
+
+	retval = i2c_master_send(ts->client, &addr, 1);
+	if (retval < 0)
+		return retval;
+
+	retval = i2c_master_recv(ts->client, values, length);
+
+	return (retval < 0) ? retval : 0;
+}
+
+static s32 ttsp_i2c_write_block_data(void *handle, u8 addr,
+	u8 length, const void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval;
+
+	ts->wr_buf[0] = addr;
+	memcpy(&ts->wr_buf[1], values, length);
+
+	retval = i2c_master_send(ts->client, ts->wr_buf, length+1);
+
+	return (retval < 0) ? retval : 0;
+}
+
+static s32 ttsp_i2c_tch_ext(void *handle, void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval = 0;
+
+	/*
+	 * TODO: Add custom touch extension handling code here
+	 * set: retval < 0 for any returned system errors,
+	 *	retval = 0 if normal touch handling is required,
+	 *	retval > 0 if normal touch handling is *not* required
+	 */
+	if (!ts || !values)
+		retval = -EIO;
+
+	return retval;
+}
+static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct cyttsp_i2c *ts;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -EIO;
+
+	/* allocate and clear memory */
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		dev_dbg(&client->dev, "%s: Error, kzalloc.\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* register driver_data */
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	ts->ops.write = ttsp_i2c_write_block_data;
+	ts->ops.read = ttsp_i2c_read_block_data;
+	ts->ops.ext = ttsp_i2c_tch_ext;
+	ts->ops.dev = &client->dev;
+	ts->ops.dev->bus = &i2c_bus_type;
+
+	ts->ttsp_client = cyttsp_core_init(&ts->ops, &client->dev);
+	if (IS_ERR(ts->ttsp_client)) {
+		int retval = PTR_ERR(ts->ttsp_client);
+		kfree(ts);
+		return retval;
+	}
+
+	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
+
+	return 0;
+}
+
+
+/* registered in driver struct */
+static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+{
+	struct cyttsp_i2c *ts;
+
+	ts = i2c_get_clientdata(client);
+	cyttsp_core_release(ts->ttsp_client);
+	kfree(ts);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	return cyttsp_suspend(dev_get_drvdata(&client->dev));
+}
+
+static int cyttsp_i2c_resume(struct i2c_client *client)
+{
+	return cyttsp_resume(dev_get_drvdata(&client->dev));
+}
+#endif
+
+static const struct i2c_device_id cyttsp_i2c_id[] = {
+	{ CY_I2C_NAME, 0 },  { }
+};
+
+static struct i2c_driver cyttsp_i2c_driver = {
+	.driver = {
+		.name = CY_I2C_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_i2c_probe,
+	.remove = __devexit_p(cyttsp_i2c_remove),
+	.id_table = cyttsp_i2c_id,
+#ifdef CONFIG_PM
+	.suspend = cyttsp_i2c_suspend,
+	.resume = cyttsp_i2c_resume,
+#endif
+};
+
+static int __init cyttsp_i2c_init(void)
+{
+	return i2c_add_driver(&cyttsp_i2c_driver);
+}
+
+static void __exit cyttsp_i2c_exit(void)
+{
+	return i2c_del_driver(&cyttsp_i2c_driver);
+}
+
+module_init(cyttsp_i2c_init);
+module_exit(cyttsp_i2c_exit);
+
+MODULE_ALIAS("i2c:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v3 3/3] 3/3 spi: Cypress TTSP G3 MTDEV SPI Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (9 preceding siblings ...)
  2010-12-29 19:17 ` [v3 2/3] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver Kevin McNeely
@ 2010-12-29 19:17 ` Kevin McNeely
  2011-01-05  0:54 ` [v4 1/3] 1/3 Touchscreen: Cypress TTSP G3 Core Driver Kevin McNeely
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2010-12-29 19:17 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Mike Frysinger, Henrik Rydberg,
	Alan Cox, linux-input, linux-kernel

Cypress TTSP Gen3 SPI Device Driver.
Provides spi communications modules for the
Cypress TTSP Gen3 MTDEV Core Driver.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
Changes since v2:
- Fixed first line of multi-line comments to follow style guide

 drivers/input/touchscreen/Kconfig      |   12 ++
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/cyttsp_spi.c |  314 ++++++++++++++++++++++++++++++++
 3 files changed, 327 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_spi.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index e1a37f5..ba3b3c5 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -141,6 +141,18 @@ config TOUCHSCREEN_CYTTSP_I2C
 	  To compile this driver as a module, choose M here: the
 	  module will be called cyttsp-i2c.
 
+config TOUCHSCREEN_CYTTSP_SPI
+	tristate "Cypress TTSP spi touchscreen"
+	depends on SPI_MASTER && TOUCHSCREEN_CYTTSP_CORE
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your  with an SPI interface.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp-spi.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 88ee091..6c6d4bb 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)    += cyttsp_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)    += cyttsp_spi.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100644
index 0000000..7559e52
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -0,0 +1,314 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#define CY_SPI_WR_OP      0x00 /* r/~w */
+#define CY_SPI_RD_OP      0x01
+#define CY_SPI_CMD_BYTES  4
+#define CY_SPI_SYNC_BYTE  2
+#define CY_SPI_SYNC_ACK1  0x62 /* from protocol v.2 */
+#define CY_SPI_SYNC_ACK2  0x9D /* from protocol v.2 */
+#define CY_SPI_DATA_SIZE  128
+#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+#define CY_SPI_BITS_PER_WORD 8
+
+struct cyttsp_spi {
+	struct cyttsp_bus_ops ops;
+	struct spi_device *spi_client;
+	void *ttsp_client;
+	u8 wr_buf[CY_SPI_DATA_BUF_SIZE];
+	u8 rd_buf[CY_SPI_DATA_BUF_SIZE];
+};
+
+static void spi_complete(void *arg)
+{
+	complete(arg);
+}
+
+static int spi_sync_tmo(struct cyttsp_spi *ts, struct spi_message *message)
+{
+	DECLARE_COMPLETION_ONSTACK(done);
+	int status;
+
+	message->complete = spi_complete;
+	message->context = &done;
+	status = spi_async(ts->spi_client, message);
+	if (status == 0) {
+		int ret = wait_for_completion_interruptible_timeout(&done, HZ);
+		if (!ret) {
+			dev_dbg(ts->ops.dev, "%s: timeout\n", __func__);
+			status = -EIO;
+		} else
+			status = message->status;
+	}
+	message->context = NULL;
+	return status;
+}
+
+static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts,
+			    u8 reg, u8 *buf, int length)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer[2];
+	u8 *wr_buf = ts->wr_buf;
+	u8 *rd_buf = ts->rd_buf;
+	int retval;
+
+	if (length > CY_SPI_DATA_SIZE) {
+		dev_dbg(ts->ops.dev, "%s: length %d is too big.\n",
+			__func__, length);
+		return -EINVAL;
+	}
+
+	memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
+	memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
+
+	wr_buf[0] = 0x00; /* header byte 0 */
+	wr_buf[1] = 0xFF; /* header byte 1 */
+	wr_buf[2] = reg;  /* reg index */
+	wr_buf[3] = op;   /* r/~w */
+	if (op == CY_SPI_WR_OP)
+		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+
+	memset((void *)xfer, 0, sizeof(xfer));
+	spi_message_init(&msg);
+	xfer[0].tx_buf = wr_buf;
+	xfer[0].rx_buf = rd_buf;
+	if (op == CY_SPI_WR_OP) {
+		xfer[0].len = length + CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+	} else if (op == CY_SPI_RD_OP) {
+		xfer[0].len = CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+
+		xfer[1].rx_buf = buf;
+		xfer[1].len = length;
+		spi_message_add_tail(&xfer[1], &msg);
+	}
+
+	retval = spi_sync_tmo(ts, &msg);
+	if (retval < 0) {
+		dev_dbg(ts->ops.dev, "%s: spi sync error %d, len=%d, op=%d\n",
+			__func__, retval, xfer[1].len, op);
+		retval = 0;
+	}
+
+	if (op == CY_SPI_RD_OP) {
+		if ((rd_buf[CY_SPI_SYNC_BYTE] == CY_SPI_SYNC_ACK1) &&
+			(rd_buf[CY_SPI_SYNC_BYTE+1] == CY_SPI_SYNC_ACK2))
+			retval = 0;
+		else {
+			int i;
+			for (i = 0; i < (CY_SPI_CMD_BYTES); i++)
+				dev_dbg(ts->ops.dev,
+					"%s: test rd_buf[%d]:0x%02x\n",
+					__func__, i, rd_buf[i]);
+			for (i = 0; i < (length); i++)
+				dev_dbg(ts->ops.dev,
+					"%s: test buf[%d]:0x%02x\n",
+					__func__, i, buf[i]);
+			retval = 1;
+		}
+	}
+	return retval;
+}
+
+static int cyttsp_spi_xfer(u8 op, struct cyttsp_spi *ts,
+			    u8 reg, u8 *buf, int length)
+{
+	int tries;
+	int retval;
+
+	if (op == CY_SPI_RD_OP) {
+		for (tries = CY_NUM_RETRY; tries; tries--) {
+			retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+			if (retval == 0)
+				break;
+			else
+				msleep(20);
+		}
+	} else {
+		retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+	}
+
+	return retval;
+}
+
+static s32 ttsp_spi_read_block_data(void *handle, u8 addr,
+				    u8 length, void *data)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval;
+
+	retval = cyttsp_spi_xfer(CY_SPI_RD_OP, ts, addr, data, length);
+	if (retval < 0)
+		dev_dbg(ts->ops.dev,  "%s: ttsp_spi_read_block_data failed\n",
+			__func__);
+
+	/*
+	 * Do not print the above error if the data sync bytes were not found.
+	 * This is a normal condition for the bootloader loader startup and need
+	 * to retry until data sync bytes are found.
+	 */
+	if (retval > 0)
+		retval = -1;	/* now signal fail; so retry can be done */
+
+	return retval;
+}
+
+static s32 ttsp_spi_write_block_data(void *handle, u8 addr,
+				     u8 length, const void *data)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval;
+
+	retval = cyttsp_spi_xfer(CY_SPI_WR_OP, ts, addr, (void *)data, length);
+	if (retval < 0)
+		dev_dbg(ts->ops.dev, "%s: ttsp_spi_write_block_data failed\n",
+			__func__);
+
+	if (retval == -EIO)
+		return 0;
+	else
+		return retval;
+}
+
+static s32 ttsp_spi_tch_ext(void *handle, void *values)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval = 0;
+
+	/*
+	 * TODO: Add custom touch extension handling code here
+	 * set: retval < 0 for any returned system errors,
+	 *	retval = 0 if normal touch handling is required,
+	 *	retval > 0 if normal touch handling is *not* required
+	 */
+
+	if (!ts || !values)
+		retval = -EIO;
+
+	return retval;
+}
+
+static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts;
+	int retval;
+
+	/* Set up SPI*/
+	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+	spi->mode = SPI_MODE_0;
+	retval = spi_setup(spi);
+	if (retval < 0) {
+		dev_dbg(&spi->dev, "%s: SPI setup error %d\n",
+			__func__, retval);
+		return retval;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		dev_dbg(&spi->dev, "%s: Error, kzalloc\n", __func__);
+		return -ENOMEM;
+	}
+
+	ts->spi_client = spi;
+	dev_set_drvdata(&spi->dev, ts);
+	ts->ops.write = ttsp_spi_write_block_data;
+	ts->ops.read = ttsp_spi_read_block_data;
+	ts->ops.ext = ttsp_spi_tch_ext;
+	ts->ops.dev = &spi->dev;
+
+	ts->ttsp_client = cyttsp_core_init(&ts->ops, &spi->dev);
+	if (IS_ERR(ts->ttsp_client)) {
+		int retval = PTR_ERR(ts->ttsp_client);
+		kfree(ts);
+		return retval;
+	}
+
+	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
+
+	return 0;
+}
+
+static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev);
+
+	cyttsp_core_release(ts->ttsp_client);
+	kfree(ts);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	return cyttsp_suspend(dev_get_drvdata(&spi->dev));
+}
+
+static int cyttsp_spi_resume(struct spi_device *spi)
+{
+	return cyttsp_resume(dev_get_drvdata(&spi->dev));
+}
+#endif
+
+static struct spi_driver cyttsp_spi_driver = {
+	.driver = {
+		.name = CY_SPI_NAME,
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_spi_probe,
+	.remove = __devexit_p(cyttsp_spi_remove),
+#ifdef CONFIG_PM
+	.suspend = cyttsp_spi_suspend,
+	.resume = cyttsp_spi_resume,
+#endif
+};
+
+static int __init cyttsp_spi_init(void)
+{
+	return spi_register_driver(&cyttsp_spi_driver);
+}
+module_init(cyttsp_spi_init);
+
+static void __exit cyttsp_spi_exit(void)
+{
+	spi_unregister_driver(&cyttsp_spi_driver);
+}
+module_exit(cyttsp_spi_exit);
+
+MODULE_ALIAS("spi:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-29 19:17 ` [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
@ 2010-12-30  6:04   ` Shubhrajyoti Datta
  2011-01-05  0:45     ` Kevin McNeely
  2010-12-31 11:53   ` Henrik Rydberg
  2011-01-04  1:50   ` Hong Liu
  2 siblings, 1 reply; 70+ messages in thread
From: Shubhrajyoti Datta @ 2010-12-30  6:04 UTC (permalink / raw)
  To: Kevin McNeely, Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Henrik Rydberg, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

Hi Kevin,
Some minor comments.

> -----Original Message-----
> From: linux-input-owner@vger.kernel.org [mailto:linux-input-
> owner@vger.kernel.org] On Behalf Of Kevin McNeely
> Sent: Thursday, December 30, 2010 12:48 AM
> To: Dmitry Torokhov
> Cc: David Brown; Trilok Soni; Kevin McNeely; Dmitry Torokhov; Henrik
> Rydberg; Samuel Ortiz; Eric Miao; Mike Frysinger; Alan Cox; linux-
> input@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
>
> Cypress TTSP Gen3 Core Driver.
> Core Driver includes platform data definition file,
> core driver definition file, and core touchscreen
> touch handling of device data. Generates
> multi-touch input events.
>
> Signed-off-by: Kevin McNeely <kev@cypress.com>
> ---
> Changes since v2:
> - Simplified Protocol A
> - Modified pointed out driver writing style
>
>  drivers/input/touchscreen/Kconfig       |    5 +
>  drivers/input/touchscreen/Makefile      |    1 +
>  drivers/input/touchscreen/cyttsp_core.c |  808
> +++++++++++++++++++++++++++++++
>  drivers/input/touchscreen/cyttsp_core.h |   55 +++
>  include/linux/input/cyttsp.h            |   68 +++
>  5 files changed, 937 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/input/touchscreen/cyttsp_core.c
>  create mode 100644 drivers/input/touchscreen/cyttsp_core.h
>  create mode 100644 include/linux/input/cyttsp.h
>
> diff --git a/drivers/input/touchscreen/Kconfig
> b/drivers/input/touchscreen/Kconfig
> index 06ea8da..7d886bc 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called cy8ctmg110_ts.
>
> +config TOUCHSCREEN_CYTTSP_CORE
> +	bool "Cypress TTSP touchscreen core"
> +	help
> +	  Always activated for Cypress TTSP touchscreen
> +
>  config TOUCHSCREEN_DA9034
>  	tristate "Touchscreen support for Dialog Semiconductor DA9034"
>  	depends on PMIC_DA903X
> diff --git a/drivers/input/touchscreen/Makefile
> b/drivers/input/touchscreen/Makefile
> index 7cc1b4f..b6f1ba8 100644
> --- a/drivers/input/touchscreen/Makefile
> +++ b/drivers/input/touchscreen/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+=
> atmel_tsadcc.o
>  obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
>  obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
>  obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
> +obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
>  obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
>  obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
>  obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
> diff --git a/drivers/input/touchscreen/cyttsp_core.c
> b/drivers/input/touchscreen/cyttsp_core.c
> new file mode 100644
> index 0000000..21a342f
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp_core.c
> @@ -0,0 +1,808 @@
> +/*
> + * Core Source for:
> + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
> + * For use with Cypress Txx3xx parts.
> + * Supported parts include:
> + * CY8CTST341
> + * CY8CTMA340
> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> along
> + * with this program; if not, write to the Free Software Foundation,
> Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
> + *
> + */
> +
> +#include "cyttsp_core.h"
> +
> +#include <linux/delay.h>
> +#include <linux/input.h>
> +#include <linux/gpio.h>
> +#include <linux/interrupt.h>
> +#include <linux/slab.h>
> +
> +/* Bootloader File 0 offset */
> +#define CY_BL_FILE0       0x00
> +/* Bootloader command directive */
> +#define CY_BL_CMD         0xFF
> +/* Bootloader Exit and Verify Checksum command */
> +#define CY_BL_EXIT        0xA5
> +/* Bootloader number of command keys */
> +#define CY_NUM_BL_KEYS    8
> +/* Bootloader default command keys */
> +#define CY_BL_KEY0 0
> +#define CY_BL_KEY1 1
> +#define CY_BL_KEY2 2
> +#define CY_BL_KEY3 3
> +#define CY_BL_KEY4 4
> +#define CY_BL_KEY5 5
> +#define CY_BL_KEY6 6
> +#define CY_BL_KEY7 7
> +
> +/* helpers */
> +#define GET_NUM_TOUCHES(x)          ((x) & 0x0F)
> +#define IS_LARGE_AREA(x)            (((x) & 0x10) >> 4)
> +#define IS_BAD_PKT(x)               ((x) & 0x20)
> +#define IS_VALID_APP(x)             ((x) & 0x01)
> +#define IS_OPERATIONAL_ERR(x)       ((x) & 0x3F)
> +#define GET_HSTMODE(reg)            ((reg & 0x70) >> 4)
> +#define GET_BOOTLOADERMODE(reg)     ((reg & 0x10) >> 4)
> +
> +#define CY_REG_BASE                 0x00
> +#define CY_REG_ACT_DIST             0x1E
> +#define CY_REG_ACT_INTRVL           0x1D
> +#define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
> +#define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
> +#define CY_MAXZ                     255
> +#define CY_DELAY_DFLT               20 /* ms */
> +#define CY_DELAY_MAX                (500/CY_DELAY_DFLT) /* half second
*/
> +#define CY_ACT_DIST_DFLT            0xF8
> +#define CY_HNDSHK_BIT               0x80
> +/* device mode bits */
> +#define CY_OPERATE_MODE             0x00
> +#define CY_SYSINFO_MODE             0x10
> +/* power mode select bits */
> +#define CY_SOFT_RESET_MODE          0x01 /* return to Bootloader mode
*/
> +#define CY_DEEP_SLEEP_MODE          0x02
> +#define CY_LOW_POWER_MODE           0x04
> +
> +/* TrueTouch Standard Product Gen3 interface definition */
> +struct cyttsp_xydata {
> +	u8 hst_mode;
> +	u8 tt_mode;
> +	u8 tt_stat;
> +	u8 tch1_xhi;
> +	u8 tch1_xlo;
> +	u8 tch1_yhi;
> +	u8 tch1_ylo;
> +	u8 tch1_z;
> +	u8 unused;
> +	u8 tch2_xhi;
> +	u8 tch2_xlo;
> +	u8 tch2_yhi;
> +	u8 tch2_ylo;
> +	u8 tch2_z;
> +	u8 unused_grp[13];
> +	u8 tt_undef[3];
> +	u8 act_dist;
> +	u8 tt_reserved;
> +};
> +
> +/* TTSP System Information interface definition */
> +struct cyttsp_sysinfo_data {
> +	u8 hst_mode;
> +	u8 mfg_cmd;
> +	u8 mfg_stat;
> +	u8 cid[3];
> +	u8 tt_undef1;
> +	u8 uid[8];
> +	u8 bl_verh;
> +	u8 bl_verl;
> +	u8 tts_verh;
> +	u8 tts_verl;
> +	u8 app_idh;
> +	u8 app_idl;
> +	u8 app_verh;
> +	u8 app_verl;
> +	u8 tt_undef[5];
> +	u8 scn_typ;
> +	u8 act_intrvl;
> +	u8 tch_tmout;
> +	u8 lp_intrvl;
> +};
> +
> +/* TTSP Bootloader Register Map interface definition */
> +#define CY_BL_CHKSUM_OK 0x01
> +struct cyttsp_bootloader_data {
> +	u8 bl_file;
> +	u8 bl_status;
> +	u8 bl_error;
> +	u8 blver_hi;
> +	u8 blver_lo;
> +	u8 bld_blver_hi;
> +	u8 bld_blver_lo;
> +	u8 ttspver_hi;
> +	u8 ttspver_lo;
> +	u8 appid_hi;
> +	u8 appid_lo;
> +	u8 appver_hi;
> +	u8 appver_lo;
> +	u8 cid_0;
> +	u8 cid_1;
> +	u8 cid_2;
> +};
> +
> +struct cyttsp_tch {
> +	u16 x;
> +	u16 y;
> +	u8 z;
> +};
> +
> +struct cyttsp {
> +	struct device *dev;
> +	int irq;
> +	struct input_dev *input;
> +	struct mutex mutex;
> +	char phys[32];
> +	const struct bus_type *bus_type;
> +	const struct cyttsp_platform_data *platform_data;
> +	struct cyttsp_bus_ops *bus_ops;
> +	struct cyttsp_xydata xy_data;
> +	struct cyttsp_bootloader_data bl_data;
> +	struct cyttsp_sysinfo_data sysinfo_data;
> +	struct completion bl_ready;
> +	enum cyttsp_powerstate power_state;
> +};
> +
> +static const u8 bl_command[] = {
> +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> +	CY_BL_KEY6, CY_BL_KEY7
> +};
> +
> +static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
> +	u8 length, void *buf)
> +{
> +	int retval;
> +	int tries;
> +
> +	if (!buf || !length)
> +		return -EIO;
> +
> +	for (tries = 0, retval = -1;
> +		tries < CY_NUM_RETRY && (retval < 0);
> +		tries++)
> +		retval = ts->bus_ops->read(ts->bus_ops, command, length,
buf);
> +
> +	return retval;
> +}
> +
> +static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
> +	u8 length, void *buf)
> +{
> +	int retval;
> +	if (!buf || !length)
> +		return -EIO;
> +
> +	retval = ts->bus_ops->write(ts->bus_ops, command, length, buf);
> +
> +	return retval;
> +}
> +
> +static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
> +{
> +	int retval;
> +
> +	if (!buf)
> +		return -EIO;
> +
> +	retval = ts->bus_ops->ext(ts->bus_ops, buf);
> +
> +	return retval;
> +}
> +
> +static int cyttsp_load_bl_regs(struct cyttsp *ts)
> +{
> +	int retval;
> +
> +	memset(&(ts->bl_data), 0, sizeof(struct cyttsp_bootloader_data));
> +
> +	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
> +		sizeof(ts->bl_data), &(ts->bl_data));
> +
> +	return retval;
> +}
> +
> +static int cyttsp_bl_app_valid(struct cyttsp *ts)
> +{
> +	int retval;
> +
> +	retval = cyttsp_load_bl_regs(ts);
> +
> +	if (retval < 0)
> +		return -ENODEV;
> +
> +	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) {
> +		if (IS_VALID_APP(ts->bl_data.bl_status)) {
> +			dev_dbg(ts->dev, "%s: App found; normal boot\n",
> +				__func__);
> +			return 0;
> +		} else {
> +			dev_dbg(ts->dev, "%s: NO APP; load firmware!!\n",
> +				__func__);
> +			return -ENODEV;
> +		}
> +	} else if (GET_HSTMODE(ts->bl_data.bl_file) == CY_OPERATE_MODE) {
> +		if (!(IS_OPERATIONAL_ERR(ts->bl_data.bl_status))) {
> +			dev_dbg(ts->dev, "%s: Operational\n",
> +				__func__);
> +			return 1;
> +		} else {
> +			dev_dbg(ts->dev, "%s: Operational failure\n",
> +				__func__);
> +			return -ENODEV;
> +		}
> +	} else {
> +		dev_dbg(ts->dev, "%s: Non-Operational failure\n",
> +			__func__);
> +			return -ENODEV;
> +	}
> +
> +}
> +
> +static int cyttsp_exit_bl_mode(struct cyttsp *ts)
> +{
> +	int retval;
> +	int tries;
> +	u8 bl_cmd[sizeof(bl_command)];
> +
> +	memcpy(bl_cmd, bl_command, sizeof(bl_command));
> +	if (ts->platform_data->bl_keys)
> +		memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
> +			ts->platform_data->bl_keys, sizeof(bl_command));
> +
> +	dev_dbg(ts->dev,
> +		"%s: bl_cmd= "
> +		"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X
%02X\n",
> +		__func__, bl_cmd[0], bl_cmd[1], bl_cmd[2],
> +		bl_cmd[3], bl_cmd[4], bl_cmd[5], bl_cmd[6],
> +		bl_cmd[7], bl_cmd[8], bl_cmd[9], bl_cmd[10]);
> +
> +	retval = ttsp_write_block_data(ts, CY_REG_BASE,
> +		sizeof(bl_cmd), (void *)bl_cmd);
> +	if (retval < 0)
> +		return retval;
> +
> +	/* wait for TTSP Device to complete switch to Operational mode */
> +	tries = 0;
> +	do {
> +		msleep(CY_DELAY_DFLT);
> +		retval = cyttsp_load_bl_regs(ts);
> +	} while (!((retval == 0) &&
> +		!GET_BOOTLOADERMODE(ts->bl_data.bl_status)) &&
> +		(tries++ < CY_DELAY_MAX));
> +
> +	dev_dbg(ts->dev, "%s: check bl ready tries=%d ret=%d stat=%02X\n",
> +		__func__, tries, retval, ts->bl_data.bl_status);
> +
> +	if (retval < 0)
> +		return retval;
> +	else if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
> +		return -ENODEV;
> +	else
> +		return 0;
> +}
> +
> +static int cyttsp_set_operational_mode(struct cyttsp *ts)
> +{
> +	int retval;
> +	int tries;
> +	u8 cmd = CY_OPERATE_MODE;
> +
> +	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd),
&cmd);
> +
> +	if (retval < 0)
> +		return retval;
> +
> +	/* wait for TTSP Device to complete switch to Operational mode */
> +	tries = 0;
> +	do {
> +		msleep(CY_DELAY_DFLT);
> +		retval = ttsp_read_block_data(ts, CY_REG_BASE,
> +			sizeof(ts->xy_data), &(ts->xy_data));
> +	} while (!((retval == 0) &&
> +		(ts->xy_data.act_dist == CY_ACT_DIST_DFLT)) &&
> +		(tries++ < CY_DELAY_MAX));
> +
> +	dev_dbg(ts->dev, "%s: check op ready tries=%d ret=%d dist=%02X\n",
> +		__func__, tries, retval, ts->xy_data.act_dist);
> +
> +	return retval;
> +}
> +
> +static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
> +{
> +	int retval;
> +	int tries;
> +	u8 cmd = CY_SYSINFO_MODE;
> +
> +	memset(&(ts->sysinfo_data), 0, sizeof(struct
cyttsp_sysinfo_data));
> +
> +	/* switch to sysinfo mode */
> +	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd),
&cmd);
> +	if (retval < 0)
> +		return retval;
> +
> +	/* read sysinfo registers */
> +	tries = 0;
> +	do {
> +		msleep(CY_DELAY_DFLT);
> +		retval = ttsp_read_block_data(ts, CY_REG_BASE,
> +			sizeof(ts->sysinfo_data), &(ts->sysinfo_data));
> +	} while (!((retval == 0) &&
> +		!((ts->sysinfo_data.tts_verh == 0) &&
> +		(ts->sysinfo_data.tts_verl == 0))) &&
> +		(tries++ < CY_DELAY_MAX));
> +
> +	dev_dbg(ts->dev, "%s: check sysinfo ready tries=%d ret=%d\n",
> +		__func__, tries, retval);
> +
> +	dev_info(ts->dev, "%s: tv=%02X%02X ai=0x%02X%02X "
> +		"av=0x%02X%02X ci=0x%02X%02X%02X\n", "cyttsp",
> +		ts->sysinfo_data.tts_verh, ts->sysinfo_data.tts_verl,
> +		ts->sysinfo_data.app_idh, ts->sysinfo_data.app_idl,
> +		ts->sysinfo_data.app_verh, ts->sysinfo_data.app_verl,
> +		ts->sysinfo_data.cid[0], ts->sysinfo_data.cid[1],
> +		ts->sysinfo_data.cid[2]);
> +
> +	return retval;
> +}
> +
> +static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
> +{
> +	int retval = 0;
> +
> +	if (ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT ||
> +		ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT ||
> +		ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT) {
> +
> +		u8 intrvl_ray[3];
> +
> +		intrvl_ray[0] = ts->platform_data->act_intrvl;
> +		intrvl_ray[1] = ts->platform_data->tch_tmout;
> +		intrvl_ray[2] = ts->platform_data->lp_intrvl;
> +
> +		/* set intrvl registers */
> +		retval = ttsp_write_block_data(ts,
> +				CY_REG_ACT_INTRVL,
> +				sizeof(intrvl_ray), intrvl_ray);
> +
> +		msleep(CY_DELAY_DFLT);
> +	}
> +
> +	return retval;
> +}
> +
> +static int cyttsp_soft_reset(struct cyttsp *ts)
> +{
> +	int retval;
> +	u8 cmd = CY_SOFT_RESET_MODE;
> +
> +	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd),
&cmd);
> +	if (retval < 0)
> +		return retval;
> +
> +	/* wait for interrupt to set ready completion */
> +	INIT_COMPLETION(ts->bl_ready);
> +
> +	retval = wait_for_completion_interruptible_timeout(&ts->bl_ready,
> +		msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
> +
> +	if (retval > 0)
> +		retval = 0;
> +
> +	return retval;
> +}
> +
> +static int cyttsp_act_dist_setup(struct cyttsp *ts)
> +{
> +	int retval;
> +	u8 act_dist_setup;
> +
> +	/* Init gesture; active distance setup */
> +	act_dist_setup = ts->platform_data->act_dist;
> +	retval = ttsp_write_block_data(ts, CY_REG_ACT_DIST,
> +		sizeof(act_dist_setup), &act_dist_setup);
> +
> +	return retval;
> +}
> +
> +static int cyttsp_hndshk(struct cyttsp *ts, u8 hst_mode)
> +{
> +	int retval;
> +	u8 cmd;
> +
> +	cmd = hst_mode & CY_HNDSHK_BIT ?
> +		hst_mode & ~CY_HNDSHK_BIT :
> +		hst_mode | CY_HNDSHK_BIT;
> +
> +	retval = ttsp_write_block_data(ts, CY_REG_BASE,
> +		sizeof(cmd), (u8 *)&cmd);
> +
> +	return retval;
> +}
> +
> +/* process current touches */
> +static int cyttsp_xy_worker(struct cyttsp *ts)
> +{
> +	u8 num_cur_tch = 0;
> +	u16 x;
> +	u16 y;
> +	u8 z;
> +
> +	/* Get touch data from CYTTSP device */
> +	if (ttsp_read_block_data(ts,
> +		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
> +		return 0;
> +
> +	/* touch extension handling */
> +	if (ttsp_tch_ext(ts, &ts->xy_data))
> +		return 0;
> +
> +	/* provide flow control handshake */
> +	if (ts->platform_data->use_hndshk)
> +		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
> +			return 0;
> +
> +	/* determine number of currently active touches */
> +	num_cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
> +
> +	/* check for any error conditions */
> +	if (ts->power_state == CY_IDLE_STATE)
> +		return 0;
> +	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
> +		return -1;
> +	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
> +		/* terminate all active tracks */
> +		num_cur_tch = 0;
> +		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
> +	} else if (num_cur_tch > 2) {
> +		/* terminate all active tracks */
> +		num_cur_tch = 0;
> +		dev_dbg(ts->dev, "%s: Num touch error detected\n",
__func__);
> +	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
> +		/* terminate all active tracks */
> +		num_cur_tch = 0;
> +		dev_dbg(ts->dev, "%s: Invalid buffer detected\n",
__func__);
> +	}
> +
> +	/* send touches */
> +	if (!num_cur_tch)
> +		/* terminate previous active touch */
> +		input_mt_sync(ts->input);
> +
> +	if (num_cur_tch) {
> +		/* send touch 1 */
> +		/*
> +		 * If there is only one current active touch,
> +		 * it will be reported in the touch 1 regardless
> +		 * if it was reported in the touch 2 previously
> +		 */
> +		x = (ts->xy_data.tch1_xhi << 8) + ts->xy_data.tch1_xlo;
> +		y = (ts->xy_data.tch1_yhi << 8) + ts->xy_data.tch1_ylo;
> +		z = ts->xy_data.tch1_z;
> +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> +		input_mt_sync(ts->input);
> +	}
> +
> +	if (num_cur_tch > 1) {
> +		/* send touch 2 */
> +		x = (ts->xy_data.tch2_xhi << 8) + ts->xy_data.tch2_xlo;
> +		y = (ts->xy_data.tch2_yhi << 8) + ts->xy_data.tch2_ylo;
> +		z = ts->xy_data.tch2_z;
> +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> +		input_mt_sync(ts->input);
> +	}
> +
> +	input_sync(ts->input);
> +
> +	return 0;
> +}
> +
> +static void cyttsp_pr_state(struct cyttsp *ts)
> +{
> +	static char *cyttsp_powerstate_string[] = {
> +		"IDLE",
> +		"ACTIVE",
> +		"LOW_PWR",
> +		"SLEEP",
> +		"BOOTLOADER",
> +		"INVALID"
> +	};
> +
> +	dev_info(ts->dev, "%s: %s\n", __func__,
> +		ts->power_state < CY_INVALID_STATE ?
> +		cyttsp_powerstate_string[ts->power_state] :
> +		"INVALID");
> +}
> +
> +static irqreturn_t cyttsp_irq(int irq, void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +	int retval;
> +
> +	if (ts->power_state == CY_BL_STATE)
> +		complete(&ts->bl_ready);
> +	else {
> +		/* process the touches */
> +		retval = cyttsp_xy_worker(ts);
> +
> +		if (retval < 0) {
> +			/*
> +			 * TTSP device has reset back to bootloader mode.
> +			 * Restore to operational mode.
> +			 */
> +			retval = cyttsp_exit_bl_mode(ts);
> +			if (retval)
> +				ts->power_state = CY_IDLE_STATE;
> +			else
> +				ts->power_state = CY_ACTIVE_STATE;
> +			cyttsp_pr_state(ts);
> +		}
> +	}
> +	return IRQ_HANDLED;
> +}
> +
> +static int cyttsp_power_on(struct cyttsp *ts)
> +{
> +	int retval = 0;
> +
> +	if (!ts)
> +		return -ENOMEM;
> +
> +	ts->power_state = CY_BL_STATE;
> +
> +	/* enable interrupts */
> +	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
> +		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> +		ts->platform_data->name, ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	retval = cyttsp_soft_reset(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	retval = cyttsp_bl_app_valid(ts);
> +	if (retval < 0)
> +		goto bypass;
> +	else if (retval > 0)
> +		goto no_bl_bypass;
> +
> +	retval = cyttsp_exit_bl_mode(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	ts->power_state = CY_IDLE_STATE;
> +
> +no_bl_bypass:
> +	retval = cyttsp_set_sysinfo_mode(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	retval = cyttsp_set_sysinfo_regs(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	retval = cyttsp_set_operational_mode(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	/* init active distance */
> +	retval = cyttsp_act_dist_setup(ts);
> +	if (retval < 0)
> +		goto bypass;
> +
> +	ts->power_state = CY_ACTIVE_STATE;
> +	retval = 0;
> +
> +bypass:
> +	cyttsp_pr_state(ts);
> +	return retval;
> +}
> +
> +#ifdef CONFIG_PM
> +int cyttsp_resume(void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +	int retval = 0;
> +	struct cyttsp_xydata xydata;
> +
> +	if (ts->platform_data->use_sleep && (ts->power_state !=
> +		CY_ACTIVE_STATE)) {
> +		if (ts->platform_data->wakeup) {
> +			retval = ts->platform_data->wakeup();
> +			if (retval < 0)
> +				dev_dbg(ts->dev, "%s: Error, wakeup
failed!\n",
> +					__func__);
> +		} else {
> +			dev_dbg(ts->dev, "%s: Error, wakeup not
implemented "
> +				"(check board file).\n", __func__);
> +			retval = -ENOSYS;
> +		}
> +		if (!(retval < 0)) {
> +			retval = ttsp_read_block_data(ts, CY_REG_BASE,
> +				sizeof(xydata), &xydata);
> +			if (!(retval < 0) &&
!GET_HSTMODE(xydata.hst_mode))
> +				ts->power_state = CY_ACTIVE_STATE;
> +		}
> +	}
> +	dev_dbg(ts->dev, "%s: Wake Up %s\n", __func__,
> +		(retval < 0) ? "FAIL" : "PASS");
> +	return retval;
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_resume);
> +
> +int cyttsp_suspend(void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +	u8 sleep_mode = 0;
> +	int retval = 0;
> +
> +	if (ts->platform_data->use_sleep &&
> +		(ts->power_state == CY_ACTIVE_STATE)) {
> +		sleep_mode = CY_DEEP_SLEEP_MODE;
> +		retval = ttsp_write_block_data(ts,
> +			CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
> +		if (!(retval < 0))
> +			ts->power_state = CY_SLEEP_STATE;
> +	}
> +	dev_dbg(ts->dev, "%s: Sleep Power state is %s\n", __func__,
> +		(ts->power_state == CY_ACTIVE_STATE) ?
> +		"ACTIVE" :
> +		((ts->power_state == CY_SLEEP_STATE) ?
> +		"SLEEP" : "LOW POWER"));
> +	return retval;
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_suspend);
> +#endif
> +
> +static int cyttsp_open(struct input_dev *dev)
> +{
> +	struct cyttsp *ts = input_get_drvdata(dev);
> +
> +	return cyttsp_power_on(ts);
> +}
> +
> +void cyttsp_core_release(void *handle)
> +{
> +	struct cyttsp *ts = handle;
> +
> +	if (ts) {
> +		mutex_destroy(&ts->mutex);
> +		free_irq(ts->irq, ts);
> +		input_unregister_device(ts->input);
> +		if (ts->platform_data->exit)
> +			ts->platform_data->exit();
> +		kfree(ts);
> +	}
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_core_release);
> +
> +static void cyttsp_close(struct input_dev *dev)
> +{
> +	struct cyttsp *ts = input_get_drvdata(dev);
> +
> +	free_irq(ts->irq, ts);
> +}
> +
> +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device
> *dev)
You may consider devinit as called only from probe.

> +{
> +	struct input_dev *input_device;
> +
> +	struct cyttsp *ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> +
> +	if (!ts) {
> +		dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
> +		goto error_alloc_data;
> +	}
> +
> +	if (dev == NULL || bus_ops == NULL) {
> +		kfree(ts);
> +		goto error_alloc_data;
> +	}
> +
> +	mutex_init(&ts->mutex);
> +	ts->dev = dev;
> +	ts->platform_data = dev->platform_data;
> +	ts->bus_ops = bus_ops;
> +	init_completion(&ts->bl_ready);
> +
> +	if (ts->platform_data->init) {
> +		if (ts->platform_data->init()) {
> +			dev_dbg(ts->dev, "%s: Error, platform init
failed!\n",
> +				__func__);
> +			goto error_init;
> +		}
> +	}
> +
> +	ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
> +	if (ts->irq <= 0) {
> +		dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
> +			__func__);
> +			goto error_init;
> +	}
> +
> +	/* Create the input device and register it. */
> +	input_device = input_allocate_device();
> +	if (!input_device) {
> +		dev_dbg(ts->dev, "%s: Error, failed to allocate input
> device\n",
> +			__func__);
> +		goto error_input_allocate_device;
> +	}
> +
> +	ts->input = input_device;
> +	input_device->name = ts->platform_data->name;
> +	snprintf(ts->phys, sizeof(ts->phys), "%s", dev_name(dev));
> +	input_device->phys = ts->phys;
> +	input_device->dev.parent = ts->dev;
> +	ts->bus_type = bus_ops->dev->bus;
> +	input_device->open = cyttsp_open;
> +	input_device->close = cyttsp_close;
> +	input_set_drvdata(input_device, ts);
> +
> +	__set_bit(EV_SYN, input_device->evbit);
> +	__set_bit(EV_KEY, input_device->evbit);
> +	__set_bit(EV_ABS, input_device->evbit);
> +
> +	input_set_abs_params(input_device, ABS_MT_POSITION_X,
> +		0, ts->platform_data->maxx, 0, 0);
> +	input_set_abs_params(input_device, ABS_MT_POSITION_Y,
> +		0, ts->platform_data->maxy, 0, 0);
> +	input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
> +		0, CY_MAXZ, 0, 0);
> +
> +	if (input_register_device(input_device)) {
> +		dev_dbg(ts->dev, "%s: Error, failed to register input
> device\n",
> +			__func__);
> +		goto error_input_register_device;
> +	}
> +
> +	goto no_error;
> +
> +error_input_register_device:
> +	input_unregister_device(input_device);
> +error_input_allocate_device:
> +	if (ts->platform_data->exit)
> +		ts->platform_data->exit();
> +error_init:
> +	mutex_destroy(&ts->mutex);
> +	kfree(ts);
Here ts is freed however we fall back and return ts.

> +error_alloc_data:
> +no_error:
> +	return ts;
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_core_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver
> core");
> +MODULE_AUTHOR("Cypress");
> +
> diff --git a/drivers/input/touchscreen/cyttsp_core.h
> b/drivers/input/touchscreen/cyttsp_core.h
> new file mode 100644
> index 0000000..b6fa22a
> --- /dev/null
> +++ b/drivers/input/touchscreen/cyttsp_core.h
> @@ -0,0 +1,55 @@
> +/*
> + * Header file for:
> + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
> + * For use with Cypress Txx3xx parts.
> + * Supported parts include:
> + * CY8CTST341
> + * CY8CTMA340
> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> along
> + * with this program; if not, write to the Free Software Foundation,
> Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
> + *
> + */
> +
> +
> +#ifndef __CYTTSP_CORE_H__
> +#define __CYTTSP_CORE_H__
> +
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/input/cyttsp.h>
> +
> +#define CY_NUM_RETRY                4 /* max number of retries for read
> ops */
> +
> +
> +struct cyttsp_bus_ops {
> +	s32 (*write)(void *handle, u8 addr, u8 length, const void
*values);
> +	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
> +	s32 (*ext)(void *handle, void *values);
> +	struct device *dev;
> +};
> +
> +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device
> *dev);
> +
> +void cyttsp_core_release(void *handle);
> +#ifdef CONFIG_PM
> +int cyttsp_resume(void *handle);
> +int cyttsp_suspend(void *handle);
> +#endif
> +
> +#endif /* __CYTTSP_CORE_H__ */
> diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
> new file mode 100644
> index 0000000..c3959ce
> --- /dev/null
> +++ b/include/linux/input/cyttsp.h
> @@ -0,0 +1,68 @@
> +/*
> + * Header file for:
> + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
> + * For use with Cypress Txx3xx parts.
> + * Supported parts include:
> + * CY8CTST341
> + * CY8CTMA340
> + *
> + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * version 2, and only version 2, as published by the
> + * Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> along
> + * with this program; if not, write to the Free Software Foundation,
> Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
> + *
> + */
> +#ifndef _CYTTSP_H_
> +#define _CYTTSP_H_
> +
> +#define CY_SPI_NAME "cyttsp-spi"
> +#define CY_I2C_NAME "cyttsp-i2c"
> +/* Active Power state scanning/processing refresh interval */
> +#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
> +/* touch timeout for the Active power */
> +#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
> +/* Low Power state scanning/processing refresh interval */
> +#define CY_LP_INTRVL_DFLT 0x0A /* ms */
> +/* Active distance in pixels for a gesture to be reported */
> +#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
> +
> +enum cyttsp_powerstate {
> +	CY_IDLE_STATE,
> +	CY_ACTIVE_STATE,
> +	CY_LOW_PWR_STATE,
> +	CY_SLEEP_STATE,
> +	CY_BL_STATE,
> +	CY_INVALID_STATE	/* always last in the list */
> +};
> +
> +struct cyttsp_platform_data {
> +	u32 maxx;
> +	u32 maxy;
> +	bool use_hndshk;
> +	bool use_sleep;
> +	u8 act_dist;	/* Active distance */
> +	u8 act_intrvl;  /* Active refresh interval; ms */
> +	u8 tch_tmout;   /* Active touch timeout; ms */
> +	u8 lp_intrvl;   /* Low power refresh interval; ms */
> +	int (*wakeup)(void);
> +	int (*init)(void);
> +	void (*exit)(void);
> +	char *name;
> +	s16 irq_gpio;
> +	u8 *bl_keys;
> +};
> +
> +#endif /* _CYTTSP_H_ */
> --
> 1.7.2.1
>
>
> ---------------------------------------------------------------
> This message and any attachments may contain Cypress (or its
> subsidiaries) confidential information. If it has been received
> in error, please advise the sender and immediately delete this
> message.
> ---------------------------------------------------------------
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input"
in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-29 19:17 ` [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
  2010-12-30  6:04   ` Shubhrajyoti Datta
@ 2010-12-31 11:53   ` Henrik Rydberg
  2010-12-31 12:55     ` Trilok Soni
  2011-01-03 17:03     ` Kevin McNeely
  2011-01-04  1:50   ` Hong Liu
  2 siblings, 2 replies; 70+ messages in thread
From: Henrik Rydberg @ 2010-12-31 11:53 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

Hi Kevin,

Thanks for the changes, it looks much better now. Some comments on the MT
part inline.

> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> index 06ea8da..7d886bc 100644
> --- a/drivers/input/touchscreen/Kconfig
> +++ b/drivers/input/touchscreen/Kconfig
> @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called cy8ctmg110_ts.
>  
> +config TOUCHSCREEN_CYTTSP_CORE
> +	bool "Cypress TTSP touchscreen core"
> +	help
> +	  Always activated for Cypress TTSP touchscreen
> +

Tristate please.

[...]
> +
> +struct cyttsp_tch {
> +	u16 x;
> +	u16 y;
> +	u8 z;
> +};

Does not appear to be used anywhere.

[...]
> +struct cyttsp {
> +	struct device *dev;
> +	int irq;
> +	struct input_dev *input;
> +	struct mutex mutex;

Is this really used?

> +	char phys[32];
> +	const struct bus_type *bus_type;
> +	const struct cyttsp_platform_data *platform_data;
> +	struct cyttsp_bus_ops *bus_ops;
> +	struct cyttsp_xydata xy_data;
> +	struct cyttsp_bootloader_data bl_data;
> +	struct cyttsp_sysinfo_data sysinfo_data;
> +	struct completion bl_ready;
> +	enum cyttsp_powerstate power_state;
> +};
> +
> +static const u8 bl_command[] = {
> +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> +	CY_BL_KEY6, CY_BL_KEY7
> +};

If the CY_BL* values are only used here, how about putting the numbers here directly?

[...]
> +static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
> +	u8 length, void *buf)
> +{
> +	int retval;
> +	int tries;
> +
> +	if (!buf || !length)
> +		return -EIO;

-EINVAL?

> +
> +	for (tries = 0, retval = -1;
> +		tries < CY_NUM_RETRY && (retval < 0);
> +		tries++)
> +		retval = ts->bus_ops->read(ts->bus_ops, command, length, buf);
> +
> +	return retval;
> +}

[...]
> +/* process current touches */
> +static int cyttsp_xy_worker(struct cyttsp *ts)
> +{
> +	u8 num_cur_tch = 0;

Does not appear to need initialization.

> +	u16 x;
> +	u16 y;
> +	u8 z;

Perhaps x[2], y[2] etc here.

> +
> +	/* Get touch data from CYTTSP device */
> +	if (ttsp_read_block_data(ts,
> +		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
> +		return 0;
> +
> +	/* touch extension handling */
> +	if (ttsp_tch_ext(ts, &ts->xy_data))
> +		return 0;
> +
> +	/* provide flow control handshake */
> +	if (ts->platform_data->use_hndshk)
> +		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
> +			return 0;
> +
> +	/* determine number of currently active touches */
> +	num_cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
> +
> +	/* check for any error conditions */
> +	if (ts->power_state == CY_IDLE_STATE)
> +		return 0;
> +	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
> +		return -1;
> +	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
> +		/* terminate all active tracks */
> +		num_cur_tch = 0;
> +		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
> +	} else if (num_cur_tch > 2) {
> +		/* terminate all active tracks */
> +		num_cur_tch = 0;
> +		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
> +	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
> +		/* terminate all active tracks */
> +		num_cur_tch = 0;
> +		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
> +	}
> +
> +	/* send touches */
> +	if (!num_cur_tch)
> +		/* terminate previous active touch */
> +		input_mt_sync(ts->input);
> +
> +	if (num_cur_tch) {
> +		/* send touch 1 */
> +		/*
> +		 * If there is only one current active touch,
> +		 * it will be reported in the touch 1 regardless
> +		 * if it was reported in the touch 2 previously
> +		 */

Perhaps "touch" should be "track" or "slot" here?

> +		x = (ts->xy_data.tch1_xhi << 8) + ts->xy_data.tch1_xlo;
> +		y = (ts->xy_data.tch1_yhi << 8) + ts->xy_data.tch1_ylo;
> +		z = ts->xy_data.tch1_z;

Perhaps x[0] = ... here

> +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> +		input_mt_sync(ts->input);

Then these could still be collected in a loop.

> +	}
> +
> +	if (num_cur_tch > 1) {
> +		/* send touch 2 */
> +		x = (ts->xy_data.tch2_xhi << 8) + ts->xy_data.tch2_xlo;
> +		y = (ts->xy_data.tch2_yhi << 8) + ts->xy_data.tch2_ylo;
> +		z = ts->xy_data.tch2_z;

And x[1] = ...

> +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> +		input_mt_sync(ts->input);
> +	}

Ditto.

> +
> +	input_sync(ts->input);
> +
> +	return 0;
> +}

If the in-kernel tracking module was in place, would you consider switching to the slots protocol?

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-31 11:53   ` Henrik Rydberg
@ 2010-12-31 12:55     ` Trilok Soni
  2010-12-31 13:58       ` Henrik Rydberg
  2011-01-03 17:03     ` Kevin McNeely
  1 sibling, 1 reply; 70+ messages in thread
From: Trilok Soni @ 2010-12-31 12:55 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Kevin McNeely, Dmitry Torokhov, David Brown, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

Hi Henrik,

On 12/31/2010 5:23 PM, Henrik Rydberg wrote:
> Hi Kevin,
> 
> Thanks for the changes, it looks much better now. Some comments on the MT
> part inline.
> 
>> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>> index 06ea8da..7d886bc 100644
>> --- a/drivers/input/touchscreen/Kconfig
>> +++ b/drivers/input/touchscreen/Kconfig
>> @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
>>  	  To compile this driver as a module, choose M here: the
>>  	  module will be called cy8ctmg110_ts.
>>  
>> +config TOUCHSCREEN_CYTTSP_CORE
>> +	bool "Cypress TTSP touchscreen core"
>> +	help
>> +	  Always activated for Cypress TTSP touchscreen
>> +
> 
> Tristate please.

This code is just exporting APIs and doesn't need to be modular. No module_init/exit etc.,

---Trilok Soni

-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-31 12:55     ` Trilok Soni
@ 2010-12-31 13:58       ` Henrik Rydberg
  2011-01-03  9:44         ` Trilok Soni
  0 siblings, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2010-12-31 13:58 UTC (permalink / raw)
  To: Trilok Soni
  Cc: Kevin McNeely, Dmitry Torokhov, David Brown, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

On Fri, Dec 31, 2010 at 06:25:51PM +0530, Trilok Soni wrote:
> Hi Henrik,
> 
> On 12/31/2010 5:23 PM, Henrik Rydberg wrote:
> > Hi Kevin,
> > 
> > Thanks for the changes, it looks much better now. Some comments on the MT
> > part inline.
> > 
> >> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
> >> index 06ea8da..7d886bc 100644
> >> --- a/drivers/input/touchscreen/Kconfig
> >> +++ b/drivers/input/touchscreen/Kconfig
> >> @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
> >>  	  To compile this driver as a module, choose M here: the
> >>  	  module will be called cy8ctmg110_ts.
> >>  
> >> +config TOUCHSCREEN_CYTTSP_CORE
> >> +	bool "Cypress TTSP touchscreen core"
> >> +	help
> >> +	  Always activated for Cypress TTSP touchscreen
> >> +
> > 
> > Tristate please.
> 
> This code is just exporting APIs and doesn't need to be modular. No module_init/exit etc.,

Any particular reason why "grep cytt /proc/kallsyms | wc" should be
non-zero when no suitable hardware is available?

Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-31 13:58       ` Henrik Rydberg
@ 2011-01-03  9:44         ` Trilok Soni
  0 siblings, 0 replies; 70+ messages in thread
From: Trilok Soni @ 2011-01-03  9:44 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Kevin McNeely, Dmitry Torokhov, David Brown, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel


Hi Henrik,

On 12/31/2010 7:28 PM, Henrik Rydberg wrote:
> On Fri, Dec 31, 2010 at 06:25:51PM +0530, Trilok Soni wrote:
>> Hi Henrik,
>>
>> On 12/31/2010 5:23 PM, Henrik Rydberg wrote:
>>> Hi Kevin,
>>>
>>> Thanks for the changes, it looks much better now. Some comments on the MT
>>> part inline.
>>>
>>>> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>>>> index 06ea8da..7d886bc 100644
>>>> --- a/drivers/input/touchscreen/Kconfig
>>>> +++ b/drivers/input/touchscreen/Kconfig
>>>> @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
>>>>  	  To compile this driver as a module, choose M here: the
>>>>  	  module will be called cy8ctmg110_ts.
>>>>  
>>>> +config TOUCHSCREEN_CYTTSP_CORE
>>>> +	bool "Cypress TTSP touchscreen core"
>>>> +	help
>>>> +	  Always activated for Cypress TTSP touchscreen
>>>> +
>>>
>>> Tristate please.
>>
>> This code is just exporting APIs and doesn't need to be modular. No module_init/exit etc.,
> 
> Any particular reason why "grep cytt /proc/kallsyms | wc" should be
> non-zero when no suitable hardware is available?
> 

Ok. Let's make it tristate then. Thanks.

---Trilok Soni


-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-31 11:53   ` Henrik Rydberg
  2010-12-31 12:55     ` Trilok Soni
@ 2011-01-03 17:03     ` Kevin McNeely
  2011-01-03 18:45       ` Henrik Rydberg
  1 sibling, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2011-01-03 17:03 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

Hi Henrik,

Thanks for your comments. Comments and questions inline below...

> -----Original Message-----
> From: Henrik Rydberg [mailto:rydberg@euromail.se]
> Sent: Friday, December 31, 2010 3:53 AM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Samuel Ortiz; Eric
Miao;
> Mike Frysinger; Alan Cox; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core
> Driver
> 
> Hi Kevin,
> 
> Thanks for the changes, it looks much better now. Some comments on the
> MT
> part inline.
> 
> > diff --git a/drivers/input/touchscreen/Kconfig
> b/drivers/input/touchscreen/Kconfig
> > index 06ea8da..7d886bc 100644
> > --- a/drivers/input/touchscreen/Kconfig
> > +++ b/drivers/input/touchscreen/Kconfig
> > @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called cy8ctmg110_ts.
> >
> > +config TOUCHSCREEN_CYTTSP_CORE
> > +	bool "Cypress TTSP touchscreen core"
> > +	help
> > +	  Always activated for Cypress TTSP touchscreen
> > +
> 
> Tristate please.

This will be changed.

> 
> [...]
> > +
> > +struct cyttsp_tch {
> > +	u16 x;
> > +	u16 y;
> > +	u8 z;
> > +};
> 
> Does not appear to be used anywhere.

This will be removed.

> 
> [...]
> > +struct cyttsp {
> > +	struct device *dev;
> > +	int irq;
> > +	struct input_dev *input;
> > +	struct mutex mutex;
> 
> Is this really used?

No. This will be removed.

> 
> > +	char phys[32];
> > +	const struct bus_type *bus_type;
> > +	const struct cyttsp_platform_data *platform_data;
> > +	struct cyttsp_bus_ops *bus_ops;
> > +	struct cyttsp_xydata xy_data;
> > +	struct cyttsp_bootloader_data bl_data;
> > +	struct cyttsp_sysinfo_data sysinfo_data;
> > +	struct completion bl_ready;
> > +	enum cyttsp_powerstate power_state;
> > +};
> > +
> > +static const u8 bl_command[] = {
> > +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> > +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> > +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> > +	CY_BL_KEY6, CY_BL_KEY7
> > +};
> 
> If the CY_BL* values are only used here, how about putting the numbers
> here directly?

This will be done.

> 
> [...]
> > +static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
> > +	u8 length, void *buf)
> > +{
> > +	int retval;
> > +	int tries;
> > +
> > +	if (!buf || !length)
> > +		return -EIO;
> 
> -EINVAL?

This will be changed.

> 
> > +
> > +	for (tries = 0, retval = -1;
> > +		tries < CY_NUM_RETRY && (retval < 0);
> > +		tries++)
> > +		retval = ts->bus_ops->read(ts->bus_ops, command, length,
> buf);
> > +
> > +	return retval;
> > +}
> 
> [...]
> > +/* process current touches */
> > +static int cyttsp_xy_worker(struct cyttsp *ts)
> > +{
> > +	u8 num_cur_tch = 0;
> 
> Does not appear to need initialization.

This will be cleaned up.

> 
> > +	u16 x;
> > +	u16 y;
> > +	u8 z;
> 
> Perhaps x[2], y[2] etc here.

This will be implemented.

> 
> > +
> > +	/* Get touch data from CYTTSP device */
> > +	if (ttsp_read_block_data(ts,
> > +		CY_REG_BASE, sizeof(struct cyttsp_xydata),
&ts->xy_data))
> > +		return 0;
> > +
> > +	/* touch extension handling */
> > +	if (ttsp_tch_ext(ts, &ts->xy_data))
> > +		return 0;
> > +
> > +	/* provide flow control handshake */
> > +	if (ts->platform_data->use_hndshk)
> > +		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
> > +			return 0;
> > +
> > +	/* determine number of currently active touches */
> > +	num_cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
> > +
> > +	/* check for any error conditions */
> > +	if (ts->power_state == CY_IDLE_STATE)
> > +		return 0;
> > +	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
> > +		return -1;
> > +	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
> > +		/* terminate all active tracks */
> > +		num_cur_tch = 0;
> > +		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
> > +	} else if (num_cur_tch > 2) {
> > +		/* terminate all active tracks */
> > +		num_cur_tch = 0;
> > +		dev_dbg(ts->dev, "%s: Num touch error detected\n",
> __func__);
> > +	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
> > +		/* terminate all active tracks */
> > +		num_cur_tch = 0;
> > +		dev_dbg(ts->dev, "%s: Invalid buffer detected\n",
> __func__);
> > +	}
> > +
> > +	/* send touches */
> > +	if (!num_cur_tch)
> > +		/* terminate previous active touch */
> > +		input_mt_sync(ts->input);
> > +
> > +	if (num_cur_tch) {
> > +		/* send touch 1 */
> > +		/*
> > +		 * If there is only one current active touch,
> > +		 * it will be reported in the touch 1 regardless
> > +		 * if it was reported in the touch 2 previously
> > +		 */
> 
> Perhaps "touch" should be "track" or "slot" here?

I plan to keep the "touch" in order to match our part documentation.

> 
> > +		x = (ts->xy_data.tch1_xhi << 8) + ts->xy_data.tch1_xlo;
> > +		y = (ts->xy_data.tch1_yhi << 8) + ts->xy_data.tch1_ylo;
> > +		z = ts->xy_data.tch1_z;
> 
> Perhaps x[0] = ... here

This will be implemented.

> 
> > +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> > +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> > +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> > +		input_mt_sync(ts->input);
> 
> Then these could still be collected in a loop.

The loop will be added.

> 
> > +	}
> > +
> > +	if (num_cur_tch > 1) {
> > +		/* send touch 2 */
> > +		x = (ts->xy_data.tch2_xhi << 8) + ts->xy_data.tch2_xlo;
> > +		y = (ts->xy_data.tch2_yhi << 8) + ts->xy_data.tch2_ylo;
> > +		z = ts->xy_data.tch2_z;
> 
> And x[1] = ...

The same, x[1] and the loop will be added.

> 
> > +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> > +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> > +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> > +		input_mt_sync(ts->input);
> > +	}
> 
> Ditto.

The same.

> 
> > +
> > +	input_sync(ts->input);
> > +
> > +	return 0;
> > +}
> 
> If the in-kernel tracking module was in place, would you consider
> switching to the slots protocol?

Hi Henrik, can you please clarify?  Should I remove MTDEV from the patch
title?

Thanks and best regards,
Kevin

> 
> Thanks,
> Henrik

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2011-01-03 17:03     ` Kevin McNeely
@ 2011-01-03 18:45       ` Henrik Rydberg
  2011-01-03 20:50         ` Kevin McNeely
  0 siblings, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2011-01-03 18:45 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

> > If the in-kernel tracking module was in place, would you consider
> > switching to the slots protocol?
> 
> Hi Henrik, can you please clarify?  Should I remove MTDEV from the patch
> title?

Let me start over - is there a way to reliably track contacts from the
device? If yes, the question is whether you would consider switching
to type B right away. If no, the question was whether you would
consider a switch to type B if there was a in-kernel tracking module
to use. I understand if there are other reasons to stay with type A, I
am mostly curious.

And perhaps MTDEV is a bit misplaced in the title, unless it has
something to do with the device.

Thanks,
Henrik

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2011-01-03 18:45       ` Henrik Rydberg
@ 2011-01-03 20:50         ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2011-01-03 20:50 UTC (permalink / raw)
  To: Henrik Rydberg
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

Hi Henrik,

The market we are currently servicing requires Protocol A and we are
trying to meet those submission requirements in the near term.

With Protocol A available to the market, we will immediately work on a
Protocol B driver which will take advantage of track id information that
our device can provide.  For that effort, I would sincerely appreciate
information about testing (in-kernel tracking module?).

Thank you and best regards,
Kevin


> -----Original Message-----
> From: Henrik Rydberg [mailto:rydberg@euromail.se]
> Sent: Monday, January 03, 2011 10:46 AM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Samuel Ortiz; Eric
Miao;
> Mike Frysinger; Alan Cox; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core
> Driver
> 
> > > If the in-kernel tracking module was in place, would you consider
> > > switching to the slots protocol?
> >
> > Hi Henrik, can you please clarify?  Should I remove MTDEV from the
> patch
> > title?
> 
> Let me start over - is there a way to reliably track contacts from the
> device? If yes, the question is whether you would consider switching
> to type B right away. If no, the question was whether you would
> consider a switch to type B if there was a in-kernel tracking module
> to use. I understand if there are other reasons to stay with type A, I
> am mostly curious.
> 
> And perhaps MTDEV is a bit misplaced in the title, unless it has
> something to do with the device.
> 
> Thanks,
> Henrik

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v3 2/3] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver
  2010-12-29 19:17 ` [v3 2/3] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver Kevin McNeely
@ 2011-01-04  1:45   ` Hong Liu
  2011-01-05  0:37     ` Kevin McNeely
  0 siblings, 1 reply; 70+ messages in thread
From: Hong Liu @ 2011-01-04  1:45 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Henrik Rydberg, Alan Cox, linux-input,
	linux-kernel

On Thu, 2010-12-30 at 03:17 +0800, Kevin McNeely wrote:
[...]
> +
> +/* registered in driver struct */
> +static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
> +{
> +	struct cyttsp_i2c *ts;
> +
> +	ts = i2c_get_clientdata(client);
> +	cyttsp_core_release(ts->ttsp_client);
> +	kfree(ts);
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int cyttsp_i2c_suspend(struct i2c_client *client, pm_message_t message)
> +{
> +	return cyttsp_suspend(dev_get_drvdata(&client->dev));
> +}
> +
> +static int cyttsp_i2c_resume(struct i2c_client *client)
> +{
> +	return cyttsp_resume(dev_get_drvdata(&client->dev));
> +}
> +#endif

I think what we get here is a pointer to cyttsp_i2c, and we need to pass
cyttsp_i2c->ttsp_client to cyttsp_suspend/resume.

Thanks,
Hong

> +
> +static const struct i2c_device_id cyttsp_i2c_id[] = {
> +	{ CY_I2C_NAME, 0 },  { }
> +};
> +
> +static struct i2c_driver cyttsp_i2c_driver = {
> +	.driver = {
> +		.name = CY_I2C_NAME,
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = cyttsp_i2c_probe,
> +	.remove = __devexit_p(cyttsp_i2c_remove),
> +	.id_table = cyttsp_i2c_id,
> +#ifdef CONFIG_PM
> +	.suspend = cyttsp_i2c_suspend,
> +	.resume = cyttsp_i2c_resume,
> +#endif
> +};
> +
> +static int __init cyttsp_i2c_init(void)
> +{
> +	return i2c_add_driver(&cyttsp_i2c_driver);
> +}
> +
> +static void __exit cyttsp_i2c_exit(void)
> +{
> +	return i2c_del_driver(&cyttsp_i2c_driver);
> +}
> +
> +module_init(cyttsp_i2c_init);
> +module_exit(cyttsp_i2c_exit);
> +
> +MODULE_ALIAS("i2c:cyttsp");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
> +MODULE_AUTHOR("Cypress");
> +MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);



^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-29 19:17 ` [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver Kevin McNeely
  2010-12-30  6:04   ` Shubhrajyoti Datta
  2010-12-31 11:53   ` Henrik Rydberg
@ 2011-01-04  1:50   ` Hong Liu
  2011-01-05  0:38     ` Kevin McNeely
  2 siblings, 1 reply; 70+ messages in thread
From: Hong Liu @ 2011-01-04  1:50 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Henrik Rydberg,
	Samuel Ortiz, Eric Miao, Mike Frysinger, Alan Cox, linux-input,
	linux-kernel

On Thu, 2010-12-30 at 03:17 +0800, Kevin McNeely wrote:
[...]

> +
> +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *dev)
> +{
> +       struct input_dev *input_device;
> +
> +       struct cyttsp *ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> +
> +       if (!ts) {
> +               dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
> +               goto error_alloc_data;
> +       }

ts->dev is not assigned yet.

Thanks,
Hong

> +
> +       if (dev == NULL || bus_ops == NULL) {
> +               kfree(ts);
> +               goto error_alloc_data;
> +       }
> +
> +       mutex_init(&ts->mutex);
> +       ts->dev = dev;
> +       ts->platform_data = dev->platform_data;
> +       ts->bus_ops = bus_ops;
> +       init_completion(&ts->bl_ready);
> +
> +       if (ts->platform_data->init) {
> +               if (ts->platform_data->init()) {
> +                       dev_dbg(ts->dev, "%s: Error, platform init failed!\n",
> +                               __func__);
> +                       goto error_init;
> +               }
> +       }
> +
> +       ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
> +       if (ts->irq <= 0) {
> +               dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
> +                       __func__);
> +                       goto error_init;
> +       }
> +
> +       /* Create the input device and register it. */
> +       input_device = input_allocate_device();
> +       if (!input_device) {
> +               dev_dbg(ts->dev, "%s: Error, failed to allocate input device\n",
> +                       __func__);
> +               goto error_input_allocate_device;
> +       }
> +
> +       ts->input = input_device;
> +       input_device->name = ts->platform_data->name;
> +       snprintf(ts->phys, sizeof(ts->phys), "%s", dev_name(dev));
> +       input_device->phys = ts->phys;
> +       input_device->dev.parent = ts->dev;
> +       ts->bus_type = bus_ops->dev->bus;
> +       input_device->open = cyttsp_open;
> +       input_device->close = cyttsp_close;
> +       input_set_drvdata(input_device, ts);
> +
> +       __set_bit(EV_SYN, input_device->evbit);
> +       __set_bit(EV_KEY, input_device->evbit);
> +       __set_bit(EV_ABS, input_device->evbit);
> +
> +       input_set_abs_params(input_device, ABS_MT_POSITION_X,
> +               0, ts->platform_data->maxx, 0, 0);
> +       input_set_abs_params(input_device, ABS_MT_POSITION_Y,
> +               0, ts->platform_data->maxy, 0, 0);
> +       input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
> +               0, CY_MAXZ, 0, 0);
> +
> +       if (input_register_device(input_device)) {
> +               dev_dbg(ts->dev, "%s: Error, failed to register input device\n",
> +                       __func__);
> +               goto error_input_register_device;
> +       }
> +
> +       goto no_error;
> +
> +error_input_register_device:
> +       input_unregister_device(input_device);
> +error_input_allocate_device:
> +       if (ts->platform_data->exit)
> +               ts->platform_data->exit();
> +error_init:
> +       mutex_destroy(&ts->mutex);
> +       kfree(ts);
> +error_alloc_data:
> +no_error:
> +       return ts;
> +}
> +EXPORT_SYMBOL_GPL(cyttsp_core_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
> +MODULE_AUTHOR("Cypress");



^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [v3 2/3] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver
  2011-01-04  1:45   ` Hong Liu
@ 2011-01-05  0:37     ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2011-01-05  0:37 UTC (permalink / raw)
  To: Hong Liu
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Henrik Rydberg, Alan Cox, linux-input,
	linux-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="UTF-8", Size: 2797 bytes --]

Hello Hong,

The pointers will be fixed in v4.

Thank you,
Kevin

> -----Original Message-----
> From: Hong Liu [mailto:hong.liu@intel.com]
> Sent: Monday, January 03, 2011 5:46 PM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Samuel Ortiz; Eric Miao;
> Mike Frysinger; Henrik Rydberg; Alan Cox; linux-input@vger.kernel.org;
> linux-kernel@vger.kernel.org
> Subject: Re: [v3 2/3] 2/3 i2c: Cypress TTSP G3 MTDEV I2C Device Driver
> 
> On Thu, 2010-12-30 at 03:17 +0800, Kevin McNeely wrote:
> [...]
> > +
> > +/* registered in driver struct */
> > +static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
> > +{
> > +	struct cyttsp_i2c *ts;
> > +
> > +	ts = i2c_get_clientdata(client);
> > +	cyttsp_core_release(ts->ttsp_client);
> > +	kfree(ts);
> > +	return 0;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +static int cyttsp_i2c_suspend(struct i2c_client *client,
> pm_message_t message)
> > +{
> > +	return cyttsp_suspend(dev_get_drvdata(&client->dev));
> > +}
> > +
> > +static int cyttsp_i2c_resume(struct i2c_client *client)
> > +{
> > +	return cyttsp_resume(dev_get_drvdata(&client->dev));
> > +}
> > +#endif
> 
> I think what we get here is a pointer to cyttsp_i2c, and we need to
> pass
> cyttsp_i2c->ttsp_client to cyttsp_suspend/resume.
> 
> Thanks,
> Hong
> 
> > +
> > +static const struct i2c_device_id cyttsp_i2c_id[] = {
> > +	{ CY_I2C_NAME, 0 },  { }
> > +};
> > +
> > +static struct i2c_driver cyttsp_i2c_driver = {
> > +	.driver = {
> > +		.name = CY_I2C_NAME,
> > +		.owner = THIS_MODULE,
> > +	},
> > +	.probe = cyttsp_i2c_probe,
> > +	.remove = __devexit_p(cyttsp_i2c_remove),
> > +	.id_table = cyttsp_i2c_id,
> > +#ifdef CONFIG_PM
> > +	.suspend = cyttsp_i2c_suspend,
> > +	.resume = cyttsp_i2c_resume,
> > +#endif
> > +};
> > +
> > +static int __init cyttsp_i2c_init(void)
> > +{
> > +	return i2c_add_driver(&cyttsp_i2c_driver);
> > +}
> > +
> > +static void __exit cyttsp_i2c_exit(void)
> > +{
> > +	return i2c_del_driver(&cyttsp_i2c_driver);
> > +}
> > +
> > +module_init(cyttsp_i2c_init);
> > +module_exit(cyttsp_i2c_exit);
> > +
> > +MODULE_ALIAS("i2c:cyttsp");
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C
> driver");
> > +MODULE_AUTHOR("Cypress");
> > +MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
> 


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2011-01-04  1:50   ` Hong Liu
@ 2011-01-05  0:38     ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2011-01-05  0:38 UTC (permalink / raw)
  To: Hong Liu
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Henrik Rydberg,
	Samuel Ortiz, Eric Miao, Mike Frysinger, Alan Cox, linux-input,
	linux-kernel

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="UTF-8", Size: 4556 bytes --]

Hello Hong,

The uninitialized use of ts->dev will be fixed in v4.

Thank you,
Kevin


> -----Original Message-----
> From: Hong Liu [mailto:hong.liu@intel.com]
> Sent: Monday, January 03, 2011 5:50 PM
> To: Kevin McNeely
> Cc: Dmitry Torokhov; David Brown; Trilok Soni; Henrik Rydberg; Samuel
> Ortiz; Eric Miao; Mike Frysinger; Alan Cox; linux-
> input@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core
> Driver
> 
> On Thu, 2010-12-30 at 03:17 +0800, Kevin McNeely wrote:
> [...]
> 
> > +
> > +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device
> *dev)
> > +{
> > +       struct input_dev *input_device;
> > +
> > +       struct cyttsp *ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> > +
> > +       if (!ts) {
> > +               dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
> > +               goto error_alloc_data;
> > +       }
> 
> ts->dev is not assigned yet.
> 
> Thanks,
> Hong
> 
> > +
> > +       if (dev == NULL || bus_ops == NULL) {
> > +               kfree(ts);
> > +               goto error_alloc_data;
> > +       }
> > +
> > +       mutex_init(&ts->mutex);
> > +       ts->dev = dev;
> > +       ts->platform_data = dev->platform_data;
> > +       ts->bus_ops = bus_ops;
> > +       init_completion(&ts->bl_ready);
> > +
> > +       if (ts->platform_data->init) {
> > +               if (ts->platform_data->init()) {
> > +                       dev_dbg(ts->dev, "%s: Error, platform init
> failed!\n",
> > +                               __func__);
> > +                       goto error_init;
> > +               }
> > +       }
> > +
> > +       ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
> > +       if (ts->irq <= 0) {
> > +               dev_dbg(ts->dev, "%s: Error, failed to allocate
> irq\n",
> > +                       __func__);
> > +                       goto error_init;
> > +       }
> > +
> > +       /* Create the input device and register it. */
> > +       input_device = input_allocate_device();
> > +       if (!input_device) {
> > +               dev_dbg(ts->dev, "%s: Error, failed to allocate input
> device\n",
> > +                       __func__);
> > +               goto error_input_allocate_device;
> > +       }
> > +
> > +       ts->input = input_device;
> > +       input_device->name = ts->platform_data->name;
> > +       snprintf(ts->phys, sizeof(ts->phys), "%s", dev_name(dev));
> > +       input_device->phys = ts->phys;
> > +       input_device->dev.parent = ts->dev;
> > +       ts->bus_type = bus_ops->dev->bus;
> > +       input_device->open = cyttsp_open;
> > +       input_device->close = cyttsp_close;
> > +       input_set_drvdata(input_device, ts);
> > +
> > +       __set_bit(EV_SYN, input_device->evbit);
> > +       __set_bit(EV_KEY, input_device->evbit);
> > +       __set_bit(EV_ABS, input_device->evbit);
> > +
> > +       input_set_abs_params(input_device, ABS_MT_POSITION_X,
> > +               0, ts->platform_data->maxx, 0, 0);
> > +       input_set_abs_params(input_device, ABS_MT_POSITION_Y,
> > +               0, ts->platform_data->maxy, 0, 0);
> > +       input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
> > +               0, CY_MAXZ, 0, 0);
> > +
> > +       if (input_register_device(input_device)) {
> > +               dev_dbg(ts->dev, "%s: Error, failed to register input
> device\n",
> > +                       __func__);
> > +               goto error_input_register_device;
> > +       }
> > +
> > +       goto no_error;
> > +
> > +error_input_register_device:
> > +       input_unregister_device(input_device);
> > +error_input_allocate_device:
> > +       if (ts->platform_data->exit)
> > +               ts->platform_data->exit();
> > +error_init:
> > +       mutex_destroy(&ts->mutex);
> > +       kfree(ts);
> > +error_alloc_data:
> > +no_error:
> > +       return ts;
> > +}
> > +EXPORT_SYMBOL_GPL(cyttsp_core_init);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver
> core");
> > +MODULE_AUTHOR("Cypress");
> 


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 70+ messages in thread

* RE: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
  2010-12-30  6:04   ` Shubhrajyoti Datta
@ 2011-01-05  0:45     ` Kevin McNeely
  0 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2011-01-05  0:45 UTC (permalink / raw)
  To: Shubhrajyoti Datta, Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Henrik Rydberg, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

Hello Shubhrajyoti,

I have response comments in line with your comments.

Thank you,
Kevin


> -----Original Message-----
> From: Shubhrajyoti Datta [mailto:shubhrajyoti@ti.com]
> Sent: Wednesday, December 29, 2010 10:05 PM
> To: Kevin McNeely; Dmitry Torokhov
> Cc: David Brown; Trilok Soni; Henrik Rydberg; Samuel Ortiz; Eric Miao;
> Mike Frysinger; Alan Cox; linux-input@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: RE: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core
> Driver
> 
> Hi Kevin,
> Some minor comments.
> 
> > -----Original Message-----
> > From: linux-input-owner@vger.kernel.org [mailto:linux-input-
> > owner@vger.kernel.org] On Behalf Of Kevin McNeely
> > Sent: Thursday, December 30, 2010 12:48 AM
> > To: Dmitry Torokhov
> > Cc: David Brown; Trilok Soni; Kevin McNeely; Dmitry Torokhov; Henrik
> > Rydberg; Samuel Ortiz; Eric Miao; Mike Frysinger; Alan Cox; linux-
> > input@vger.kernel.org; linux-kernel@vger.kernel.org
> > Subject: [v3 1/3] 1/3 Touchscreen: Cypress TTSP G3 MTDEV Core Driver
> >
> > Cypress TTSP Gen3 Core Driver.
> > Core Driver includes platform data definition file,
> > core driver definition file, and core touchscreen
> > touch handling of device data. Generates
> > multi-touch input events.
> >
> > Signed-off-by: Kevin McNeely <kev@cypress.com>
> > ---
> > Changes since v2:
> > - Simplified Protocol A
> > - Modified pointed out driver writing style
> >
> >  drivers/input/touchscreen/Kconfig       |    5 +
> >  drivers/input/touchscreen/Makefile      |    1 +
> >  drivers/input/touchscreen/cyttsp_core.c |  808
> > +++++++++++++++++++++++++++++++
> >  drivers/input/touchscreen/cyttsp_core.h |   55 +++
> >  include/linux/input/cyttsp.h            |   68 +++
> >  5 files changed, 937 insertions(+), 0 deletions(-)
> >  create mode 100644 drivers/input/touchscreen/cyttsp_core.c
> >  create mode 100644 drivers/input/touchscreen/cyttsp_core.h
> >  create mode 100644 include/linux/input/cyttsp.h
> >
> > diff --git a/drivers/input/touchscreen/Kconfig
> > b/drivers/input/touchscreen/Kconfig
> > index 06ea8da..7d886bc 100644
> > --- a/drivers/input/touchscreen/Kconfig
> > +++ b/drivers/input/touchscreen/Kconfig
> > @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
> >  	  To compile this driver as a module, choose M here: the
> >  	  module will be called cy8ctmg110_ts.
> >
> > +config TOUCHSCREEN_CYTTSP_CORE
> > +	bool "Cypress TTSP touchscreen core"
> > +	help
> > +	  Always activated for Cypress TTSP touchscreen
> > +
> >  config TOUCHSCREEN_DA9034
> >  	tristate "Touchscreen support for Dialog Semiconductor DA9034"
> >  	depends on PMIC_DA903X
> > diff --git a/drivers/input/touchscreen/Makefile
> > b/drivers/input/touchscreen/Makefile
> > index 7cc1b4f..b6f1ba8 100644
> > --- a/drivers/input/touchscreen/Makefile
> > +++ b/drivers/input/touchscreen/Makefile
> > @@ -16,6 +16,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+=
> > atmel_tsadcc.o
> >  obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
> >  obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
> >  obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
> > +obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
> >  obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
> >  obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
> >  obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
> > diff --git a/drivers/input/touchscreen/cyttsp_core.c
> > b/drivers/input/touchscreen/cyttsp_core.c
> > new file mode 100644
> > index 0000000..21a342f
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp_core.c
> > @@ -0,0 +1,808 @@
> > +/*
> > + * Core Source for:
> > + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen
> drivers.
> > + * For use with Cypress Txx3xx parts.
> > + * Supported parts include:
> > + * CY8CTST341
> > + * CY8CTMA340
> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> > along
> > + * with this program; if not, write to the Free Software
Foundation,
> > Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> <kev@cypress.com>
> > + *
> > + */
> > +
> > +#include "cyttsp_core.h"
> > +
> > +#include <linux/delay.h>
> > +#include <linux/input.h>
> > +#include <linux/gpio.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/slab.h>
> > +
> > +/* Bootloader File 0 offset */
> > +#define CY_BL_FILE0       0x00
> > +/* Bootloader command directive */
> > +#define CY_BL_CMD         0xFF
> > +/* Bootloader Exit and Verify Checksum command */
> > +#define CY_BL_EXIT        0xA5
> > +/* Bootloader number of command keys */
> > +#define CY_NUM_BL_KEYS    8
> > +/* Bootloader default command keys */
> > +#define CY_BL_KEY0 0
> > +#define CY_BL_KEY1 1
> > +#define CY_BL_KEY2 2
> > +#define CY_BL_KEY3 3
> > +#define CY_BL_KEY4 4
> > +#define CY_BL_KEY5 5
> > +#define CY_BL_KEY6 6
> > +#define CY_BL_KEY7 7
> > +
> > +/* helpers */
> > +#define GET_NUM_TOUCHES(x)          ((x) & 0x0F)
> > +#define IS_LARGE_AREA(x)            (((x) & 0x10) >> 4)
> > +#define IS_BAD_PKT(x)               ((x) & 0x20)
> > +#define IS_VALID_APP(x)             ((x) & 0x01)
> > +#define IS_OPERATIONAL_ERR(x)       ((x) & 0x3F)
> > +#define GET_HSTMODE(reg)            ((reg & 0x70) >> 4)
> > +#define GET_BOOTLOADERMODE(reg)     ((reg & 0x10) >> 4)
> > +
> > +#define CY_REG_BASE                 0x00
> > +#define CY_REG_ACT_DIST             0x1E
> > +#define CY_REG_ACT_INTRVL           0x1D
> > +#define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
> > +#define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
> > +#define CY_MAXZ                     255
> > +#define CY_DELAY_DFLT               20 /* ms */
> > +#define CY_DELAY_MAX                (500/CY_DELAY_DFLT) /* half
> second
> */
> > +#define CY_ACT_DIST_DFLT            0xF8
> > +#define CY_HNDSHK_BIT               0x80
> > +/* device mode bits */
> > +#define CY_OPERATE_MODE             0x00
> > +#define CY_SYSINFO_MODE             0x10
> > +/* power mode select bits */
> > +#define CY_SOFT_RESET_MODE          0x01 /* return to Bootloader
> mode
> */
> > +#define CY_DEEP_SLEEP_MODE          0x02
> > +#define CY_LOW_POWER_MODE           0x04
> > +
> > +/* TrueTouch Standard Product Gen3 interface definition */
> > +struct cyttsp_xydata {
> > +	u8 hst_mode;
> > +	u8 tt_mode;
> > +	u8 tt_stat;
> > +	u8 tch1_xhi;
> > +	u8 tch1_xlo;
> > +	u8 tch1_yhi;
> > +	u8 tch1_ylo;
> > +	u8 tch1_z;
> > +	u8 unused;
> > +	u8 tch2_xhi;
> > +	u8 tch2_xlo;
> > +	u8 tch2_yhi;
> > +	u8 tch2_ylo;
> > +	u8 tch2_z;
> > +	u8 unused_grp[13];
> > +	u8 tt_undef[3];
> > +	u8 act_dist;
> > +	u8 tt_reserved;
> > +};
> > +
> > +/* TTSP System Information interface definition */
> > +struct cyttsp_sysinfo_data {
> > +	u8 hst_mode;
> > +	u8 mfg_cmd;
> > +	u8 mfg_stat;
> > +	u8 cid[3];
> > +	u8 tt_undef1;
> > +	u8 uid[8];
> > +	u8 bl_verh;
> > +	u8 bl_verl;
> > +	u8 tts_verh;
> > +	u8 tts_verl;
> > +	u8 app_idh;
> > +	u8 app_idl;
> > +	u8 app_verh;
> > +	u8 app_verl;
> > +	u8 tt_undef[5];
> > +	u8 scn_typ;
> > +	u8 act_intrvl;
> > +	u8 tch_tmout;
> > +	u8 lp_intrvl;
> > +};
> > +
> > +/* TTSP Bootloader Register Map interface definition */
> > +#define CY_BL_CHKSUM_OK 0x01
> > +struct cyttsp_bootloader_data {
> > +	u8 bl_file;
> > +	u8 bl_status;
> > +	u8 bl_error;
> > +	u8 blver_hi;
> > +	u8 blver_lo;
> > +	u8 bld_blver_hi;
> > +	u8 bld_blver_lo;
> > +	u8 ttspver_hi;
> > +	u8 ttspver_lo;
> > +	u8 appid_hi;
> > +	u8 appid_lo;
> > +	u8 appver_hi;
> > +	u8 appver_lo;
> > +	u8 cid_0;
> > +	u8 cid_1;
> > +	u8 cid_2;
> > +};
> > +
> > +struct cyttsp_tch {
> > +	u16 x;
> > +	u16 y;
> > +	u8 z;
> > +};
> > +
> > +struct cyttsp {
> > +	struct device *dev;
> > +	int irq;
> > +	struct input_dev *input;
> > +	struct mutex mutex;
> > +	char phys[32];
> > +	const struct bus_type *bus_type;
> > +	const struct cyttsp_platform_data *platform_data;
> > +	struct cyttsp_bus_ops *bus_ops;
> > +	struct cyttsp_xydata xy_data;
> > +	struct cyttsp_bootloader_data bl_data;
> > +	struct cyttsp_sysinfo_data sysinfo_data;
> > +	struct completion bl_ready;
> > +	enum cyttsp_powerstate power_state;
> > +};
> > +
> > +static const u8 bl_command[] = {
> > +	CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
> > +	CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
> > +	CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
> > +	CY_BL_KEY6, CY_BL_KEY7
> > +};
> > +
> > +static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
> > +	u8 length, void *buf)
> > +{
> > +	int retval;
> > +	int tries;
> > +
> > +	if (!buf || !length)
> > +		return -EIO;
> > +
> > +	for (tries = 0, retval = -1;
> > +		tries < CY_NUM_RETRY && (retval < 0);
> > +		tries++)
> > +		retval = ts->bus_ops->read(ts->bus_ops, command, length,
> buf);
> > +
> > +	return retval;
> > +}
> > +
> > +static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
> > +	u8 length, void *buf)
> > +{
> > +	int retval;
> > +	if (!buf || !length)
> > +		return -EIO;
> > +
> > +	retval = ts->bus_ops->write(ts->bus_ops, command, length, buf);
> > +
> > +	return retval;
> > +}
> > +
> > +static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
> > +{
> > +	int retval;
> > +
> > +	if (!buf)
> > +		return -EIO;
> > +
> > +	retval = ts->bus_ops->ext(ts->bus_ops, buf);
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_load_bl_regs(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +
> > +	memset(&(ts->bl_data), 0, sizeof(struct
cyttsp_bootloader_data));
> > +
> > +	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
> > +		sizeof(ts->bl_data), &(ts->bl_data));
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_bl_app_valid(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +
> > +	retval = cyttsp_load_bl_regs(ts);
> > +
> > +	if (retval < 0)
> > +		return -ENODEV;
> > +
> > +	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) {
> > +		if (IS_VALID_APP(ts->bl_data.bl_status)) {
> > +			dev_dbg(ts->dev, "%s: App found; normal boot\n",
> > +				__func__);
> > +			return 0;
> > +		} else {
> > +			dev_dbg(ts->dev, "%s: NO APP; load
firmware!!\n",
> > +				__func__);
> > +			return -ENODEV;
> > +		}
> > +	} else if (GET_HSTMODE(ts->bl_data.bl_file) == CY_OPERATE_MODE)
{
> > +		if (!(IS_OPERATIONAL_ERR(ts->bl_data.bl_status))) {
> > +			dev_dbg(ts->dev, "%s: Operational\n",
> > +				__func__);
> > +			return 1;
> > +		} else {
> > +			dev_dbg(ts->dev, "%s: Operational failure\n",
> > +				__func__);
> > +			return -ENODEV;
> > +		}
> > +	} else {
> > +		dev_dbg(ts->dev, "%s: Non-Operational failure\n",
> > +			__func__);
> > +			return -ENODEV;
> > +	}
> > +
> > +}
> > +
> > +static int cyttsp_exit_bl_mode(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +	int tries;
> > +	u8 bl_cmd[sizeof(bl_command)];
> > +
> > +	memcpy(bl_cmd, bl_command, sizeof(bl_command));
> > +	if (ts->platform_data->bl_keys)
> > +		memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
> > +			ts->platform_data->bl_keys, sizeof(bl_command));
> > +
> > +	dev_dbg(ts->dev,
> > +		"%s: bl_cmd= "
> > +		"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X
> %02X\n",
> > +		__func__, bl_cmd[0], bl_cmd[1], bl_cmd[2],
> > +		bl_cmd[3], bl_cmd[4], bl_cmd[5], bl_cmd[6],
> > +		bl_cmd[7], bl_cmd[8], bl_cmd[9], bl_cmd[10]);
> > +
> > +	retval = ttsp_write_block_data(ts, CY_REG_BASE,
> > +		sizeof(bl_cmd), (void *)bl_cmd);
> > +	if (retval < 0)
> > +		return retval;
> > +
> > +	/* wait for TTSP Device to complete switch to Operational mode
*/
> > +	tries = 0;
> > +	do {
> > +		msleep(CY_DELAY_DFLT);
> > +		retval = cyttsp_load_bl_regs(ts);
> > +	} while (!((retval == 0) &&
> > +		!GET_BOOTLOADERMODE(ts->bl_data.bl_status)) &&
> > +		(tries++ < CY_DELAY_MAX));
> > +
> > +	dev_dbg(ts->dev, "%s: check bl ready tries=%d ret=%d
> stat=%02X\n",
> > +		__func__, tries, retval, ts->bl_data.bl_status);
> > +
> > +	if (retval < 0)
> > +		return retval;
> > +	else if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
> > +		return -ENODEV;
> > +	else
> > +		return 0;
> > +}
> > +
> > +static int cyttsp_set_operational_mode(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +	int tries;
> > +	u8 cmd = CY_OPERATE_MODE;
> > +
> > +	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd),
> &cmd);
> > +
> > +	if (retval < 0)
> > +		return retval;
> > +
> > +	/* wait for TTSP Device to complete switch to Operational mode
*/
> > +	tries = 0;
> > +	do {
> > +		msleep(CY_DELAY_DFLT);
> > +		retval = ttsp_read_block_data(ts, CY_REG_BASE,
> > +			sizeof(ts->xy_data), &(ts->xy_data));
> > +	} while (!((retval == 0) &&
> > +		(ts->xy_data.act_dist == CY_ACT_DIST_DFLT)) &&
> > +		(tries++ < CY_DELAY_MAX));
> > +
> > +	dev_dbg(ts->dev, "%s: check op ready tries=%d ret=%d
> dist=%02X\n",
> > +		__func__, tries, retval, ts->xy_data.act_dist);
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +	int tries;
> > +	u8 cmd = CY_SYSINFO_MODE;
> > +
> > +	memset(&(ts->sysinfo_data), 0, sizeof(struct
> cyttsp_sysinfo_data));
> > +
> > +	/* switch to sysinfo mode */
> > +	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd),
> &cmd);
> > +	if (retval < 0)
> > +		return retval;
> > +
> > +	/* read sysinfo registers */
> > +	tries = 0;
> > +	do {
> > +		msleep(CY_DELAY_DFLT);
> > +		retval = ttsp_read_block_data(ts, CY_REG_BASE,
> > +			sizeof(ts->sysinfo_data), &(ts->sysinfo_data));
> > +	} while (!((retval == 0) &&
> > +		!((ts->sysinfo_data.tts_verh == 0) &&
> > +		(ts->sysinfo_data.tts_verl == 0))) &&
> > +		(tries++ < CY_DELAY_MAX));
> > +
> > +	dev_dbg(ts->dev, "%s: check sysinfo ready tries=%d ret=%d\n",
> > +		__func__, tries, retval);
> > +
> > +	dev_info(ts->dev, "%s: tv=%02X%02X ai=0x%02X%02X "
> > +		"av=0x%02X%02X ci=0x%02X%02X%02X\n", "cyttsp",
> > +		ts->sysinfo_data.tts_verh, ts->sysinfo_data.tts_verl,
> > +		ts->sysinfo_data.app_idh, ts->sysinfo_data.app_idl,
> > +		ts->sysinfo_data.app_verh, ts->sysinfo_data.app_verl,
> > +		ts->sysinfo_data.cid[0], ts->sysinfo_data.cid[1],
> > +		ts->sysinfo_data.cid[2]);
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
> > +{
> > +	int retval = 0;
> > +
> > +	if (ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT ||
> > +		ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT ||
> > +		ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT) {
> > +
> > +		u8 intrvl_ray[3];
> > +
> > +		intrvl_ray[0] = ts->platform_data->act_intrvl;
> > +		intrvl_ray[1] = ts->platform_data->tch_tmout;
> > +		intrvl_ray[2] = ts->platform_data->lp_intrvl;
> > +
> > +		/* set intrvl registers */
> > +		retval = ttsp_write_block_data(ts,
> > +				CY_REG_ACT_INTRVL,
> > +				sizeof(intrvl_ray), intrvl_ray);
> > +
> > +		msleep(CY_DELAY_DFLT);
> > +	}
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_soft_reset(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +	u8 cmd = CY_SOFT_RESET_MODE;
> > +
> > +	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd),
> &cmd);
> > +	if (retval < 0)
> > +		return retval;
> > +
> > +	/* wait for interrupt to set ready completion */
> > +	INIT_COMPLETION(ts->bl_ready);
> > +
> > +	retval =
wait_for_completion_interruptible_timeout(&ts->bl_ready,
> > +		msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
> > +
> > +	if (retval > 0)
> > +		retval = 0;
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_act_dist_setup(struct cyttsp *ts)
> > +{
> > +	int retval;
> > +	u8 act_dist_setup;
> > +
> > +	/* Init gesture; active distance setup */
> > +	act_dist_setup = ts->platform_data->act_dist;
> > +	retval = ttsp_write_block_data(ts, CY_REG_ACT_DIST,
> > +		sizeof(act_dist_setup), &act_dist_setup);
> > +
> > +	return retval;
> > +}
> > +
> > +static int cyttsp_hndshk(struct cyttsp *ts, u8 hst_mode)
> > +{
> > +	int retval;
> > +	u8 cmd;
> > +
> > +	cmd = hst_mode & CY_HNDSHK_BIT ?
> > +		hst_mode & ~CY_HNDSHK_BIT :
> > +		hst_mode | CY_HNDSHK_BIT;
> > +
> > +	retval = ttsp_write_block_data(ts, CY_REG_BASE,
> > +		sizeof(cmd), (u8 *)&cmd);
> > +
> > +	return retval;
> > +}
> > +
> > +/* process current touches */
> > +static int cyttsp_xy_worker(struct cyttsp *ts)
> > +{
> > +	u8 num_cur_tch = 0;
> > +	u16 x;
> > +	u16 y;
> > +	u8 z;
> > +
> > +	/* Get touch data from CYTTSP device */
> > +	if (ttsp_read_block_data(ts,
> > +		CY_REG_BASE, sizeof(struct cyttsp_xydata),
&ts->xy_data))
> > +		return 0;
> > +
> > +	/* touch extension handling */
> > +	if (ttsp_tch_ext(ts, &ts->xy_data))
> > +		return 0;
> > +
> > +	/* provide flow control handshake */
> > +	if (ts->platform_data->use_hndshk)
> > +		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
> > +			return 0;
> > +
> > +	/* determine number of currently active touches */
> > +	num_cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
> > +
> > +	/* check for any error conditions */
> > +	if (ts->power_state == CY_IDLE_STATE)
> > +		return 0;
> > +	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
> > +		return -1;
> > +	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
> > +		/* terminate all active tracks */
> > +		num_cur_tch = 0;
> > +		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
> > +	} else if (num_cur_tch > 2) {
> > +		/* terminate all active tracks */
> > +		num_cur_tch = 0;
> > +		dev_dbg(ts->dev, "%s: Num touch error detected\n",
> __func__);
> > +	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
> > +		/* terminate all active tracks */
> > +		num_cur_tch = 0;
> > +		dev_dbg(ts->dev, "%s: Invalid buffer detected\n",
> __func__);
> > +	}
> > +
> > +	/* send touches */
> > +	if (!num_cur_tch)
> > +		/* terminate previous active touch */
> > +		input_mt_sync(ts->input);
> > +
> > +	if (num_cur_tch) {
> > +		/* send touch 1 */
> > +		/*
> > +		 * If there is only one current active touch,
> > +		 * it will be reported in the touch 1 regardless
> > +		 * if it was reported in the touch 2 previously
> > +		 */
> > +		x = (ts->xy_data.tch1_xhi << 8) + ts->xy_data.tch1_xlo;
> > +		y = (ts->xy_data.tch1_yhi << 8) + ts->xy_data.tch1_ylo;
> > +		z = ts->xy_data.tch1_z;
> > +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> > +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> > +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> > +		input_mt_sync(ts->input);
> > +	}
> > +
> > +	if (num_cur_tch > 1) {
> > +		/* send touch 2 */
> > +		x = (ts->xy_data.tch2_xhi << 8) + ts->xy_data.tch2_xlo;
> > +		y = (ts->xy_data.tch2_yhi << 8) + ts->xy_data.tch2_ylo;
> > +		z = ts->xy_data.tch2_z;
> > +		input_report_abs(ts->input, ABS_MT_POSITION_X, x);
> > +		input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
> > +		input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, z);
> > +		input_mt_sync(ts->input);
> > +	}
> > +
> > +	input_sync(ts->input);
> > +
> > +	return 0;
> > +}
> > +
> > +static void cyttsp_pr_state(struct cyttsp *ts)
> > +{
> > +	static char *cyttsp_powerstate_string[] = {
> > +		"IDLE",
> > +		"ACTIVE",
> > +		"LOW_PWR",
> > +		"SLEEP",
> > +		"BOOTLOADER",
> > +		"INVALID"
> > +	};
> > +
> > +	dev_info(ts->dev, "%s: %s\n", __func__,
> > +		ts->power_state < CY_INVALID_STATE ?
> > +		cyttsp_powerstate_string[ts->power_state] :
> > +		"INVALID");
> > +}
> > +
> > +static irqreturn_t cyttsp_irq(int irq, void *handle)
> > +{
> > +	struct cyttsp *ts = handle;
> > +	int retval;
> > +
> > +	if (ts->power_state == CY_BL_STATE)
> > +		complete(&ts->bl_ready);
> > +	else {
> > +		/* process the touches */
> > +		retval = cyttsp_xy_worker(ts);
> > +
> > +		if (retval < 0) {
> > +			/*
> > +			 * TTSP device has reset back to bootloader
mode.
> > +			 * Restore to operational mode.
> > +			 */
> > +			retval = cyttsp_exit_bl_mode(ts);
> > +			if (retval)
> > +				ts->power_state = CY_IDLE_STATE;
> > +			else
> > +				ts->power_state = CY_ACTIVE_STATE;
> > +			cyttsp_pr_state(ts);
> > +		}
> > +	}
> > +	return IRQ_HANDLED;
> > +}
> > +
> > +static int cyttsp_power_on(struct cyttsp *ts)
> > +{
> > +	int retval = 0;
> > +
> > +	if (!ts)
> > +		return -ENOMEM;
> > +
> > +	ts->power_state = CY_BL_STATE;
> > +
> > +	/* enable interrupts */
> > +	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
> > +		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> > +		ts->platform_data->name, ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +
> > +	retval = cyttsp_soft_reset(ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +
> > +	retval = cyttsp_bl_app_valid(ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +	else if (retval > 0)
> > +		goto no_bl_bypass;
> > +
> > +	retval = cyttsp_exit_bl_mode(ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +
> > +	ts->power_state = CY_IDLE_STATE;
> > +
> > +no_bl_bypass:
> > +	retval = cyttsp_set_sysinfo_mode(ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +
> > +	retval = cyttsp_set_sysinfo_regs(ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +
> > +	retval = cyttsp_set_operational_mode(ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +
> > +	/* init active distance */
> > +	retval = cyttsp_act_dist_setup(ts);
> > +	if (retval < 0)
> > +		goto bypass;
> > +
> > +	ts->power_state = CY_ACTIVE_STATE;
> > +	retval = 0;
> > +
> > +bypass:
> > +	cyttsp_pr_state(ts);
> > +	return retval;
> > +}
> > +
> > +#ifdef CONFIG_PM
> > +int cyttsp_resume(void *handle)
> > +{
> > +	struct cyttsp *ts = handle;
> > +	int retval = 0;
> > +	struct cyttsp_xydata xydata;
> > +
> > +	if (ts->platform_data->use_sleep && (ts->power_state !=
> > +		CY_ACTIVE_STATE)) {
> > +		if (ts->platform_data->wakeup) {
> > +			retval = ts->platform_data->wakeup();
> > +			if (retval < 0)
> > +				dev_dbg(ts->dev, "%s: Error, wakeup
> failed!\n",
> > +					__func__);
> > +		} else {
> > +			dev_dbg(ts->dev, "%s: Error, wakeup not
> implemented "
> > +				"(check board file).\n", __func__);
> > +			retval = -ENOSYS;
> > +		}
> > +		if (!(retval < 0)) {
> > +			retval = ttsp_read_block_data(ts, CY_REG_BASE,
> > +				sizeof(xydata), &xydata);
> > +			if (!(retval < 0) &&
> !GET_HSTMODE(xydata.hst_mode))
> > +				ts->power_state = CY_ACTIVE_STATE;
> > +		}
> > +	}
> > +	dev_dbg(ts->dev, "%s: Wake Up %s\n", __func__,
> > +		(retval < 0) ? "FAIL" : "PASS");
> > +	return retval;
> > +}
> > +EXPORT_SYMBOL_GPL(cyttsp_resume);
> > +
> > +int cyttsp_suspend(void *handle)
> > +{
> > +	struct cyttsp *ts = handle;
> > +	u8 sleep_mode = 0;
> > +	int retval = 0;
> > +
> > +	if (ts->platform_data->use_sleep &&
> > +		(ts->power_state == CY_ACTIVE_STATE)) {
> > +		sleep_mode = CY_DEEP_SLEEP_MODE;
> > +		retval = ttsp_write_block_data(ts,
> > +			CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
> > +		if (!(retval < 0))
> > +			ts->power_state = CY_SLEEP_STATE;
> > +	}
> > +	dev_dbg(ts->dev, "%s: Sleep Power state is %s\n", __func__,
> > +		(ts->power_state == CY_ACTIVE_STATE) ?
> > +		"ACTIVE" :
> > +		((ts->power_state == CY_SLEEP_STATE) ?
> > +		"SLEEP" : "LOW POWER"));
> > +	return retval;
> > +}
> > +EXPORT_SYMBOL_GPL(cyttsp_suspend);
> > +#endif
> > +
> > +static int cyttsp_open(struct input_dev *dev)
> > +{
> > +	struct cyttsp *ts = input_get_drvdata(dev);
> > +
> > +	return cyttsp_power_on(ts);
> > +}
> > +
> > +void cyttsp_core_release(void *handle)
> > +{
> > +	struct cyttsp *ts = handle;
> > +
> > +	if (ts) {
> > +		mutex_destroy(&ts->mutex);
> > +		free_irq(ts->irq, ts);
> > +		input_unregister_device(ts->input);
> > +		if (ts->platform_data->exit)
> > +			ts->platform_data->exit();
> > +		kfree(ts);
> > +	}
> > +}
> > +EXPORT_SYMBOL_GPL(cyttsp_core_release);
> > +
> > +static void cyttsp_close(struct input_dev *dev)
> > +{
> > +	struct cyttsp *ts = input_get_drvdata(dev);
> > +
> > +	free_irq(ts->irq, ts);
> > +}
> > +
> > +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct
device
> > *dev)
> You may consider devinit as called only from probe.
> 

This is common initialization code.  The devinit probe is declared in
the I2C and SPI host communication files (patches 2/3 and 3/3).

> > +{
> > +	struct input_dev *input_device;
> > +
> > +	struct cyttsp *ts = kzalloc(sizeof(*ts), GFP_KERNEL);
> > +
> > +	if (!ts) {
> > +		dev_dbg(ts->dev, "%s: Error, kzalloc\n", __func__);
> > +		goto error_alloc_data;
> > +	}
> > +
> > +	if (dev == NULL || bus_ops == NULL) {
> > +		kfree(ts);
> > +		goto error_alloc_data;
> > +	}
> > +
> > +	mutex_init(&ts->mutex);
> > +	ts->dev = dev;
> > +	ts->platform_data = dev->platform_data;
> > +	ts->bus_ops = bus_ops;
> > +	init_completion(&ts->bl_ready);
> > +
> > +	if (ts->platform_data->init) {
> > +		if (ts->platform_data->init()) {
> > +			dev_dbg(ts->dev, "%s: Error, platform init
> failed!\n",
> > +				__func__);
> > +			goto error_init;
> > +		}
> > +	}
> > +
> > +	ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
> > +	if (ts->irq <= 0) {
> > +		dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
> > +			__func__);
> > +			goto error_init;
> > +	}
> > +
> > +	/* Create the input device and register it. */
> > +	input_device = input_allocate_device();
> > +	if (!input_device) {
> > +		dev_dbg(ts->dev, "%s: Error, failed to allocate input
> > device\n",
> > +			__func__);
> > +		goto error_input_allocate_device;
> > +	}
> > +
> > +	ts->input = input_device;
> > +	input_device->name = ts->platform_data->name;
> > +	snprintf(ts->phys, sizeof(ts->phys), "%s", dev_name(dev));
> > +	input_device->phys = ts->phys;
> > +	input_device->dev.parent = ts->dev;
> > +	ts->bus_type = bus_ops->dev->bus;
> > +	input_device->open = cyttsp_open;
> > +	input_device->close = cyttsp_close;
> > +	input_set_drvdata(input_device, ts);
> > +
> > +	__set_bit(EV_SYN, input_device->evbit);
> > +	__set_bit(EV_KEY, input_device->evbit);
> > +	__set_bit(EV_ABS, input_device->evbit);
> > +
> > +	input_set_abs_params(input_device, ABS_MT_POSITION_X,
> > +		0, ts->platform_data->maxx, 0, 0);
> > +	input_set_abs_params(input_device, ABS_MT_POSITION_Y,
> > +		0, ts->platform_data->maxy, 0, 0);
> > +	input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
> > +		0, CY_MAXZ, 0, 0);
> > +
> > +	if (input_register_device(input_device)) {
> > +		dev_dbg(ts->dev, "%s: Error, failed to register input
> > device\n",
> > +			__func__);
> > +		goto error_input_register_device;
> > +	}
> > +
> > +	goto no_error;
> > +
> > +error_input_register_device:
> > +	input_unregister_device(input_device);
> > +error_input_allocate_device:
> > +	if (ts->platform_data->exit)
> > +		ts->platform_data->exit();
> > +error_init:
> > +	mutex_destroy(&ts->mutex);
> > +	kfree(ts);
> Here ts is freed however we fall back and return ts.
> 

The ts pointer is returned as NULL for error condition.  This error
condition is detected by the probe function in the I2C and SPI probes
(patch 2/3 and 3/3).

> > +error_alloc_data:
> > +no_error:
> > +	return ts;
> > +}
> > +EXPORT_SYMBOL_GPL(cyttsp_core_init);
> > +
> > +MODULE_LICENSE("GPL");
> > +MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen
driver
> > core");
> > +MODULE_AUTHOR("Cypress");
> > +
> > diff --git a/drivers/input/touchscreen/cyttsp_core.h
> > b/drivers/input/touchscreen/cyttsp_core.h
> > new file mode 100644
> > index 0000000..b6fa22a
> > --- /dev/null
> > +++ b/drivers/input/touchscreen/cyttsp_core.h
> > @@ -0,0 +1,55 @@
> > +/*
> > + * Header file for:
> > + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen
> drivers.
> > + * For use with Cypress Txx3xx parts.
> > + * Supported parts include:
> > + * CY8CTST341
> > + * CY8CTMA340
> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> > along
> > + * with this program; if not, write to the Free Software
Foundation,
> > Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> <kev@cypress.com>
> > + *
> > + */
> > +
> > +
> > +#ifndef __CYTTSP_CORE_H__
> > +#define __CYTTSP_CORE_H__
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/err.h>
> > +#include <linux/input/cyttsp.h>
> > +
> > +#define CY_NUM_RETRY                4 /* max number of retries for
> read
> > ops */
> > +
> > +
> > +struct cyttsp_bus_ops {
> > +	s32 (*write)(void *handle, u8 addr, u8 length, const void
> *values);
> > +	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
> > +	s32 (*ext)(void *handle, void *values);
> > +	struct device *dev;
> > +};
> > +
> > +void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct
device
> > *dev);
> > +
> > +void cyttsp_core_release(void *handle);
> > +#ifdef CONFIG_PM
> > +int cyttsp_resume(void *handle);
> > +int cyttsp_suspend(void *handle);
> > +#endif
> > +
> > +#endif /* __CYTTSP_CORE_H__ */
> > diff --git a/include/linux/input/cyttsp.h
> b/include/linux/input/cyttsp.h
> > new file mode 100644
> > index 0000000..c3959ce
> > --- /dev/null
> > +++ b/include/linux/input/cyttsp.h
> > @@ -0,0 +1,68 @@
> > +/*
> > + * Header file for:
> > + * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen
> drivers.
> > + * For use with Cypress Txx3xx parts.
> > + * Supported parts include:
> > + * CY8CTST341
> > + * CY8CTMA340
> > + *
> > + * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or
> > + * modify it under the terms of the GNU General Public License
> > + * version 2, and only version 2, as published by the
> > + * Free Software Foundation.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public
License
> > along
> > + * with this program; if not, write to the Free Software
Foundation,
> > Inc.,
> > + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> > + *
> > + * Contact Cypress Semiconductor at www.cypress.com
> (kev@cypress.com)
> > + *
> > + */
> > +#ifndef _CYTTSP_H_
> > +#define _CYTTSP_H_
> > +
> > +#define CY_SPI_NAME "cyttsp-spi"
> > +#define CY_I2C_NAME "cyttsp-i2c"
> > +/* Active Power state scanning/processing refresh interval */
> > +#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
> > +/* touch timeout for the Active power */
> > +#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
> > +/* Low Power state scanning/processing refresh interval */
> > +#define CY_LP_INTRVL_DFLT 0x0A /* ms */
> > +/* Active distance in pixels for a gesture to be reported */
> > +#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
> > +
> > +enum cyttsp_powerstate {
> > +	CY_IDLE_STATE,
> > +	CY_ACTIVE_STATE,
> > +	CY_LOW_PWR_STATE,
> > +	CY_SLEEP_STATE,
> > +	CY_BL_STATE,
> > +	CY_INVALID_STATE	/* always last in the list */
> > +};
> > +
> > +struct cyttsp_platform_data {
> > +	u32 maxx;
> > +	u32 maxy;
> > +	bool use_hndshk;
> > +	bool use_sleep;
> > +	u8 act_dist;	/* Active distance */
> > +	u8 act_intrvl;  /* Active refresh interval; ms */
> > +	u8 tch_tmout;   /* Active touch timeout; ms */
> > +	u8 lp_intrvl;   /* Low power refresh interval; ms */
> > +	int (*wakeup)(void);
> > +	int (*init)(void);
> > +	void (*exit)(void);
> > +	char *name;
> > +	s16 irq_gpio;
> > +	u8 *bl_keys;
> > +};
> > +
> > +#endif /* _CYTTSP_H_ */
> > --
> > 1.7.2.1
> >
> >
> > ---------------------------------------------------------------
> > This message and any attachments may contain Cypress (or its
> > subsidiaries) confidential information. If it has been received
> > in error, please advise the sender and immediately delete this
> > message.
> > ---------------------------------------------------------------
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-
> input"
> in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v4 1/3] 1/3 Touchscreen: Cypress TTSP G3 Core Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (10 preceding siblings ...)
  2010-12-29 19:17 ` [v3 3/3] 3/3 spi: Cypress TTSP G3 MTDEV SPI " Kevin McNeely
@ 2011-01-05  0:54 ` Kevin McNeely
  2011-01-05  8:59   ` Henrik Rydberg
  2011-01-05  0:54 ` [v4 2/3] 2/3 i2c: Cypress TTSP G3 I2C Device Driver Kevin McNeely
  2011-01-05  0:54 ` [v4 3/3] 3/3 spi: Cypress TTSP G3 SPI " Kevin McNeely
  13 siblings, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2011-01-05  0:54 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Henrik Rydberg, Samuel Ortiz, Eric Miao, Mike Frysinger,
	Alan Cox, linux-input, linux-kernel

Cypress TTSP Gen3 Core Driver.
Core Driver includes platform data definition file,
core driver definition file, and core touchscreen
touch handling of device data. Generates
multi-touch input events.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
Changes since v3:
- Removed unused items
- replace EIO with EINVAL
- add x[], y[] and loop on mt signaling
- removed uninitialized use of ts->dev

 drivers/input/touchscreen/Kconfig       |    5 +
 drivers/input/touchscreen/Makefile      |    1 +
 drivers/input/touchscreen/cyttsp_core.c |  794 +++++++++++++++++++++++++++++++
 drivers/input/touchscreen/cyttsp_core.h |   55 +++
 include/linux/input/cyttsp.h            |   68 +++
 5 files changed, 923 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_core.c
 create mode 100644 drivers/input/touchscreen/cyttsp_core.h
 create mode 100644 include/linux/input/cyttsp.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 06ea8da..c3240b8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
 	  To compile this driver as a module, choose M here: the
 	  module will be called cy8ctmg110_ts.
 
+config TOUCHSCREEN_CYTTSP_CORE
+	tristate "Cypress TTSP touchscreen core"
+	help
+	  Always activated for Cypress TTSP touchscreen
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 7cc1b4f..b6f1ba8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 0000000..07b4840
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,794 @@
+/*
+ * Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Bootloader number of command keys */
+#define CY_NUM_BL_KEYS    8
+
+/* helpers */
+#define GET_NUM_TOUCHES(x)          ((x) & 0x0F)
+#define IS_LARGE_AREA(x)            (((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x)               ((x) & 0x20)
+#define IS_VALID_APP(x)             ((x) & 0x01)
+#define IS_OPERATIONAL_ERR(x)       ((x) & 0x3F)
+#define GET_HSTMODE(reg)            ((reg & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)     ((reg & 0x10) >> 4)
+
+#define CY_REG_BASE                 0x00
+#define CY_REG_ACT_DIST             0x1E
+#define CY_REG_ACT_INTRVL           0x1D
+#define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
+#define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
+#define CY_MAXZ                     255
+#define CY_DELAY_DFLT               20 /* ms */
+#define CY_DELAY_MAX                (500/CY_DELAY_DFLT) /* half second */
+#define CY_ACT_DIST_DFLT            0xF8
+#define CY_HNDSHK_BIT               0x80
+/* device mode bits */
+#define CY_OPERATE_MODE             0x00
+#define CY_SYSINFO_MODE             0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE          0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE          0x02
+#define CY_LOW_POWER_MODE           0x04
+
+/* TrueTouch Standard Product Gen3 interface definition */
+struct cyttsp_xydata {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	u8 tch1_xhi;
+	u8 tch1_xlo;
+	u8 tch1_yhi;
+	u8 tch1_ylo;
+	u8 tch1_z;
+	u8 unused;
+	u8 tch2_xhi;
+	u8 tch2_xlo;
+	u8 tch2_yhi;
+	u8 tch2_ylo;
+	u8 tch2_z;
+	u8 unused_grp[13];
+	u8 tt_undef[3];
+	u8 act_dist;
+	u8 tt_reserved;
+};
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[5];
+	u8 scn_typ;
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+struct cyttsp {
+	struct device *dev;
+	int irq;
+	struct input_dev *input;
+	char phys[32];
+	const struct bus_type *bus_type;
+	const struct cyttsp_platform_data *platform_data;
+	struct cyttsp_bus_ops *bus_ops;
+	struct cyttsp_xydata xy_data;
+	struct cyttsp_bootloader_data bl_data;
+	struct cyttsp_sysinfo_data sysinfo_data;
+	struct completion bl_ready;
+	enum cyttsp_powerstate power_state;
+};
+
+static const u8 bl_command[] = {
+	0x00,			/* file offset */
+	0xFF,			/* command */
+	0xA5,			/* exit bootloader command */
+	0, 1, 2, 3, 4, 5, 6, 7	/* default keys */
+};
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int retval;
+	int tries;
+
+	if (!buf || !length)
+		return -EINVAL;
+
+	for (tries = 0, retval = -1;
+		tries < CY_NUM_RETRY && (retval < 0);
+		tries++)
+		retval = ts->bus_ops->read(ts->bus_ops, command, length, buf);
+
+	return retval;
+}
+
+static int ttsp_write_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	int retval;
+	if (!buf || !length)
+		return -EINVAL;
+
+	retval = ts->bus_ops->write(ts->bus_ops, command, length, buf);
+
+	return retval;
+}
+
+static int ttsp_tch_ext(struct cyttsp *ts, void *buf)
+{
+	int retval;
+
+	if (!buf)
+		return -EIO;
+
+	retval = ts->bus_ops->ext(ts->bus_ops, buf);
+
+	return retval;
+}
+
+static int cyttsp_load_bl_regs(struct cyttsp *ts)
+{
+	int retval;
+
+	memset(&(ts->bl_data), 0, sizeof(struct cyttsp_bootloader_data));
+
+	retval =  ttsp_read_block_data(ts, CY_REG_BASE,
+		sizeof(ts->bl_data), &(ts->bl_data));
+
+	return retval;
+}
+
+static int cyttsp_bl_app_valid(struct cyttsp *ts)
+{
+	int retval;
+
+	retval = cyttsp_load_bl_regs(ts);
+
+	if (retval < 0)
+		return -ENODEV;
+
+	if (GET_BOOTLOADERMODE(ts->bl_data.bl_status)) {
+		if (IS_VALID_APP(ts->bl_data.bl_status)) {
+			dev_dbg(ts->dev, "%s: App found; normal boot\n",
+				__func__);
+			return 0;
+		} else {
+			dev_dbg(ts->dev, "%s: NO APP; load firmware!!\n",
+				__func__);
+			return -ENODEV;
+		}
+	} else if (GET_HSTMODE(ts->bl_data.bl_file) == CY_OPERATE_MODE) {
+		if (!(IS_OPERATIONAL_ERR(ts->bl_data.bl_status))) {
+			dev_dbg(ts->dev, "%s: Operational\n",
+				__func__);
+			return 1;
+		} else {
+			dev_dbg(ts->dev, "%s: Operational failure\n",
+				__func__);
+			return -ENODEV;
+		}
+	} else {
+		dev_dbg(ts->dev, "%s: Non-Operational failure\n",
+			__func__);
+			return -ENODEV;
+	}
+
+}
+
+static int cyttsp_exit_bl_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries;
+	u8 bl_cmd[sizeof(bl_command)];
+
+	memcpy(bl_cmd, bl_command, sizeof(bl_command));
+	if (ts->platform_data->bl_keys)
+		memcpy(&bl_cmd[sizeof(bl_command) - CY_NUM_BL_KEYS],
+			ts->platform_data->bl_keys, sizeof(bl_command));
+
+	dev_dbg(ts->dev,
+		"%s: bl_cmd= "
+		"%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
+		__func__, bl_cmd[0], bl_cmd[1], bl_cmd[2],
+		bl_cmd[3], bl_cmd[4], bl_cmd[5], bl_cmd[6],
+		bl_cmd[7], bl_cmd[8], bl_cmd[9], bl_cmd[10]);
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE,
+		sizeof(bl_cmd), (void *)bl_cmd);
+	if (retval < 0)
+		return retval;
+
+	/* wait for TTSP Device to complete switch to Operational mode */
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = cyttsp_load_bl_regs(ts);
+	} while (!((retval == 0) &&
+		!GET_BOOTLOADERMODE(ts->bl_data.bl_status)) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check bl ready tries=%d ret=%d stat=%02X\n",
+		__func__, tries, retval, ts->bl_data.bl_status);
+
+	if (retval < 0)
+		return retval;
+	else if (GET_BOOTLOADERMODE(ts->bl_data.bl_status))
+		return -ENODEV;
+	else
+		return 0;
+}
+
+static int cyttsp_set_operational_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries;
+	u8 cmd = CY_OPERATE_MODE;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+
+	if (retval < 0)
+		return retval;
+
+	/* wait for TTSP Device to complete switch to Operational mode */
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = ttsp_read_block_data(ts, CY_REG_BASE,
+			sizeof(ts->xy_data), &(ts->xy_data));
+	} while (!((retval == 0) &&
+		(ts->xy_data.act_dist == CY_ACT_DIST_DFLT)) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check op ready tries=%d ret=%d dist=%02X\n",
+		__func__, tries, retval, ts->xy_data.act_dist);
+
+	return retval;
+}
+
+static int cyttsp_set_sysinfo_mode(struct cyttsp *ts)
+{
+	int retval;
+	int tries;
+	u8 cmd = CY_SYSINFO_MODE;
+
+	memset(&(ts->sysinfo_data), 0, sizeof(struct cyttsp_sysinfo_data));
+
+	/* switch to sysinfo mode */
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (retval < 0)
+		return retval;
+
+	/* read sysinfo registers */
+	tries = 0;
+	do {
+		msleep(CY_DELAY_DFLT);
+		retval = ttsp_read_block_data(ts, CY_REG_BASE,
+			sizeof(ts->sysinfo_data), &(ts->sysinfo_data));
+	} while (!((retval == 0) &&
+		!((ts->sysinfo_data.tts_verh == 0) &&
+		(ts->sysinfo_data.tts_verl == 0))) &&
+		(tries++ < CY_DELAY_MAX));
+
+	dev_dbg(ts->dev, "%s: check sysinfo ready tries=%d ret=%d\n",
+		__func__, tries, retval);
+
+	dev_info(ts->dev, "%s: tv=%02X%02X ai=0x%02X%02X "
+		"av=0x%02X%02X ci=0x%02X%02X%02X\n", "cyttsp",
+		ts->sysinfo_data.tts_verh, ts->sysinfo_data.tts_verl,
+		ts->sysinfo_data.app_idh, ts->sysinfo_data.app_idl,
+		ts->sysinfo_data.app_verh, ts->sysinfo_data.app_verl,
+		ts->sysinfo_data.cid[0], ts->sysinfo_data.cid[1],
+		ts->sysinfo_data.cid[2]);
+
+	return retval;
+}
+
+static int cyttsp_set_sysinfo_regs(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	if (ts->platform_data->act_intrvl != CY_ACT_INTRVL_DFLT ||
+		ts->platform_data->tch_tmout != CY_TCH_TMOUT_DFLT ||
+		ts->platform_data->lp_intrvl != CY_LP_INTRVL_DFLT) {
+
+		u8 intrvl_ray[3];
+
+		intrvl_ray[0] = ts->platform_data->act_intrvl;
+		intrvl_ray[1] = ts->platform_data->tch_tmout;
+		intrvl_ray[2] = ts->platform_data->lp_intrvl;
+
+		/* set intrvl registers */
+		retval = ttsp_write_block_data(ts,
+				CY_REG_ACT_INTRVL,
+				sizeof(intrvl_ray), intrvl_ray);
+
+		msleep(CY_DELAY_DFLT);
+	}
+
+	return retval;
+}
+
+static int cyttsp_soft_reset(struct cyttsp *ts)
+{
+	int retval;
+	u8 cmd = CY_SOFT_RESET_MODE;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE, sizeof(cmd), &cmd);
+	if (retval < 0)
+		return retval;
+
+	/* wait for interrupt to set ready completion */
+	INIT_COMPLETION(ts->bl_ready);
+
+	retval = wait_for_completion_interruptible_timeout(&ts->bl_ready,
+		msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX));
+
+	if (retval > 0)
+		retval = 0;
+
+	return retval;
+}
+
+static int cyttsp_act_dist_setup(struct cyttsp *ts)
+{
+	int retval;
+	u8 act_dist_setup;
+
+	/* Init gesture; active distance setup */
+	act_dist_setup = ts->platform_data->act_dist;
+	retval = ttsp_write_block_data(ts, CY_REG_ACT_DIST,
+		sizeof(act_dist_setup), &act_dist_setup);
+
+	return retval;
+}
+
+static int cyttsp_hndshk(struct cyttsp *ts, u8 hst_mode)
+{
+	int retval;
+	u8 cmd;
+
+	cmd = hst_mode & CY_HNDSHK_BIT ?
+		hst_mode & ~CY_HNDSHK_BIT :
+		hst_mode | CY_HNDSHK_BIT;
+
+	retval = ttsp_write_block_data(ts, CY_REG_BASE,
+		sizeof(cmd), (u8 *)&cmd);
+
+	return retval;
+}
+
+/* process current touches */
+#define CY_MAX_TCH	2
+static int cyttsp_xy_worker(struct cyttsp *ts)
+{
+	u8 num_cur_tch;
+	u16 x[CY_MAX_TCH];
+	u16 y[CY_MAX_TCH];
+	u8 z[CY_MAX_TCH];
+	bool t[CY_MAX_TCH];
+	int i;
+
+	/* Get touch data from CYTTSP device */
+	if (ttsp_read_block_data(ts,
+		CY_REG_BASE, sizeof(struct cyttsp_xydata), &ts->xy_data))
+		return 0;
+
+	/* touch extension handling */
+	if (ttsp_tch_ext(ts, &ts->xy_data))
+		return 0;
+
+	/* provide flow control handshake */
+	if (ts->platform_data->use_hndshk)
+		if (cyttsp_hndshk(ts, ts->xy_data.hst_mode))
+			return 0;
+
+	/* determine number of currently active touches */
+	num_cur_tch = GET_NUM_TOUCHES(ts->xy_data.tt_stat);
+
+	/* check for any error conditions */
+	if (ts->power_state == CY_IDLE_STATE)
+		return 0;
+	else if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
+		return -1;
+	} else if (IS_LARGE_AREA(ts->xy_data.tt_stat) == 1) {
+		/* terminate all active tracks */
+		num_cur_tch = 0;
+		dev_dbg(ts->dev, "%s: Large area detected\n", __func__);
+	} else if (num_cur_tch > CY_MAX_TCH) {
+		/* terminate all active tracks */
+		num_cur_tch = 0;
+		dev_dbg(ts->dev, "%s: Num touch error detected\n", __func__);
+	} else if (IS_BAD_PKT(ts->xy_data.tt_mode)) {
+		/* terminate all active tracks */
+		num_cur_tch = 0;
+		dev_dbg(ts->dev, "%s: Invalid buffer detected\n", __func__);
+	}
+
+	/* send touches */
+	if (!num_cur_tch)
+		/* terminate previous active touch */
+		input_mt_sync(ts->input);
+	else {
+		/* get touch 1 */
+		/*
+		 * If there is only one current active touch,
+		 * it will be reported in the touch 1 regardless
+		 * if it was reported in the touch 2 previously
+		 */
+		x[0] = (ts->xy_data.tch1_xhi << 8) + ts->xy_data.tch1_xlo;
+		y[0] = (ts->xy_data.tch1_yhi << 8) + ts->xy_data.tch1_ylo;
+		z[0] = ts->xy_data.tch1_z;
+		t[0] = true;
+
+		/* get touch 2 */
+		if (num_cur_tch == CY_MAX_TCH) {
+			x[1] = (ts->xy_data.tch2_xhi << 8) +
+				ts->xy_data.tch2_xlo;
+			y[1] = (ts->xy_data.tch2_yhi << 8) +
+				ts->xy_data.tch2_ylo;
+			z[1] = ts->xy_data.tch2_z;
+			t[1] = true;
+		}
+
+		for (i = 0; i < CY_MAX_TCH; i++) {
+			if (t[i]) {
+				input_report_abs(ts->input,
+					ABS_MT_POSITION_X, x[i]);
+				input_report_abs(ts->input,
+					ABS_MT_POSITION_Y, y[i]);
+				input_report_abs(ts->input,
+					ABS_MT_TOUCH_MAJOR, z[i]);
+				input_mt_sync(ts->input);
+			}
+		}
+	}
+
+	input_sync(ts->input);
+
+	return 0;
+}
+
+static void cyttsp_pr_state(struct cyttsp *ts)
+{
+	static char *cyttsp_powerstate_string[] = {
+		"IDLE",
+		"ACTIVE",
+		"LOW_PWR",
+		"SLEEP",
+		"BOOTLOADER",
+		"INVALID"
+	};
+
+	dev_info(ts->dev, "%s: %s\n", __func__,
+		ts->power_state < CY_INVALID_STATE ?
+		cyttsp_powerstate_string[ts->power_state] :
+		"INVALID");
+}
+
+static irqreturn_t cyttsp_irq(int irq, void *handle)
+{
+	struct cyttsp *ts = handle;
+	int retval;
+
+	if (ts->power_state == CY_BL_STATE)
+		complete(&ts->bl_ready);
+	else {
+		/* process the touches */
+		retval = cyttsp_xy_worker(ts);
+
+		if (retval < 0) {
+			/*
+			 * TTSP device has reset back to bootloader mode.
+			 * Restore to operational mode.
+			 */
+			retval = cyttsp_exit_bl_mode(ts);
+			if (retval)
+				ts->power_state = CY_IDLE_STATE;
+			else
+				ts->power_state = CY_ACTIVE_STATE;
+			cyttsp_pr_state(ts);
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static int cyttsp_power_on(struct cyttsp *ts)
+{
+	int retval = 0;
+
+	if (!ts)
+		return -ENOMEM;
+
+	ts->power_state = CY_BL_STATE;
+
+	/* enable interrupts */
+	retval = request_threaded_irq(ts->irq, NULL, cyttsp_irq,
+		IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		ts->platform_data->name, ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_soft_reset(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_bl_app_valid(ts);
+	if (retval < 0)
+		goto bypass;
+	else if (retval > 0)
+		goto no_bl_bypass;
+
+	retval = cyttsp_exit_bl_mode(ts);
+
+	if (retval < 0)
+		goto bypass;
+
+	ts->power_state = CY_IDLE_STATE;
+
+no_bl_bypass:
+	retval = cyttsp_set_sysinfo_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_set_sysinfo_regs(ts);
+	if (retval < 0)
+		goto bypass;
+
+	retval = cyttsp_set_operational_mode(ts);
+	if (retval < 0)
+		goto bypass;
+
+	/* init active distance */
+	retval = cyttsp_act_dist_setup(ts);
+	if (retval < 0)
+		goto bypass;
+
+	ts->power_state = CY_ACTIVE_STATE;
+	retval = 0;
+
+bypass:
+	cyttsp_pr_state(ts);
+	return retval;
+}
+
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle)
+{
+	struct cyttsp *ts = handle;
+	int retval = 0;
+	struct cyttsp_xydata xydata;
+
+	if (ts->platform_data->use_sleep && (ts->power_state !=
+		CY_ACTIVE_STATE)) {
+		if (ts->platform_data->wakeup) {
+			retval = ts->platform_data->wakeup();
+			if (retval < 0)
+				dev_dbg(ts->dev, "%s: Error, wakeup failed!\n",
+					__func__);
+		} else {
+			dev_dbg(ts->dev, "%s: Error, wakeup not implemented "
+				"(check board file).\n", __func__);
+			retval = -ENOSYS;
+		}
+		if (!(retval < 0)) {
+			retval = ttsp_read_block_data(ts, CY_REG_BASE,
+				sizeof(xydata), &xydata);
+			if (!(retval < 0) && !GET_HSTMODE(xydata.hst_mode))
+				ts->power_state = CY_ACTIVE_STATE;
+		}
+	}
+	dev_dbg(ts->dev, "%s: Wake Up %s\n", __func__,
+		(retval < 0) ? "FAIL" : "PASS");
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cyttsp_resume);
+
+int cyttsp_suspend(void *handle)
+{
+	struct cyttsp *ts = handle;
+	u8 sleep_mode = 0;
+	int retval = 0;
+
+	if (ts->platform_data->use_sleep &&
+		(ts->power_state == CY_ACTIVE_STATE)) {
+		sleep_mode = CY_DEEP_SLEEP_MODE;
+		retval = ttsp_write_block_data(ts,
+			CY_REG_BASE, sizeof(sleep_mode), &sleep_mode);
+		if (!(retval < 0))
+			ts->power_state = CY_SLEEP_STATE;
+	}
+	dev_dbg(ts->dev, "%s: Sleep Power state is %s\n", __func__,
+		(ts->power_state == CY_ACTIVE_STATE) ?
+		"ACTIVE" :
+		((ts->power_state == CY_SLEEP_STATE) ?
+		"SLEEP" : "LOW POWER"));
+	return retval;
+}
+EXPORT_SYMBOL_GPL(cyttsp_suspend);
+#endif
+
+static int cyttsp_open(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	return cyttsp_power_on(ts);
+}
+
+void cyttsp_core_release(void *handle)
+{
+	struct cyttsp *ts = handle;
+
+	if (ts) {
+		free_irq(ts->irq, ts);
+		input_unregister_device(ts->input);
+		if (ts->platform_data->exit)
+			ts->platform_data->exit();
+		kfree(ts);
+	}
+}
+EXPORT_SYMBOL_GPL(cyttsp_core_release);
+
+static void cyttsp_close(struct input_dev *dev)
+{
+	struct cyttsp *ts = input_get_drvdata(dev);
+
+	free_irq(ts->irq, ts);
+}
+
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *dev)
+{
+	struct input_dev *input_device;
+
+	struct cyttsp *ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+
+	if (!ts) {
+		pr_err("%s: Error, kzalloc\n", __func__);
+		goto error_alloc_data;
+	}
+
+	if (dev == NULL || bus_ops == NULL) {
+		kfree(ts);
+		goto error_alloc_data;
+	}
+
+	ts->dev = dev;
+	ts->platform_data = dev->platform_data;
+	ts->bus_ops = bus_ops;
+	init_completion(&ts->bl_ready);
+
+	if (ts->platform_data->init) {
+		if (ts->platform_data->init()) {
+			dev_dbg(ts->dev, "%s: Error, platform init failed!\n",
+				__func__);
+			goto error_init;
+		}
+	}
+
+	ts->irq = gpio_to_irq(ts->platform_data->irq_gpio);
+	if (ts->irq <= 0) {
+		dev_dbg(ts->dev, "%s: Error, failed to allocate irq\n",
+			__func__);
+			goto error_init;
+	}
+
+	/* Create the input device and register it. */
+	input_device = input_allocate_device();
+	if (!input_device) {
+		dev_dbg(ts->dev, "%s: Error, failed to allocate input device\n",
+			__func__);
+		goto error_input_allocate_device;
+	}
+
+	ts->input = input_device;
+	input_device->name = ts->platform_data->name;
+	snprintf(ts->phys, sizeof(ts->phys), "%s", dev_name(dev));
+	input_device->phys = ts->phys;
+	input_device->dev.parent = ts->dev;
+	ts->bus_type = bus_ops->dev->bus;
+	input_device->open = cyttsp_open;
+	input_device->close = cyttsp_close;
+	input_set_drvdata(input_device, ts);
+
+	__set_bit(EV_SYN, input_device->evbit);
+	__set_bit(EV_KEY, input_device->evbit);
+	__set_bit(EV_ABS, input_device->evbit);
+
+	input_set_abs_params(input_device, ABS_MT_POSITION_X,
+		0, ts->platform_data->maxx, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_POSITION_Y,
+		0, ts->platform_data->maxy, 0, 0);
+	input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR,
+		0, CY_MAXZ, 0, 0);
+
+	if (input_register_device(input_device)) {
+		dev_dbg(ts->dev, "%s: Error, failed to register input device\n",
+			__func__);
+		goto error_input_register_device;
+	}
+
+	goto no_error;
+
+error_input_register_device:
+	input_unregister_device(input_device);
+error_input_allocate_device:
+	if (ts->platform_data->exit)
+		ts->platform_data->exit();
+error_init:
+	kfree(ts);
+error_alloc_data:
+no_error:
+	return ts;
+}
+EXPORT_SYMBOL_GPL(cyttsp_core_init);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver core");
+MODULE_AUTHOR("Cypress");
+
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
new file mode 100644
index 0000000..78001b5
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -0,0 +1,55 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+
+#ifndef __CYTTSP_CORE_H__
+#define __CYTTSP_CORE_H__
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/input/cyttsp.h>
+
+#define CY_NUM_RETRY                4 /* max number of retries for read ops */
+
+
+struct cyttsp_bus_ops {
+	s32 (*write)(void *handle, u8 addr, u8 length, const void *values);
+	s32 (*read)(void *handle, u8 addr, u8 length, void *values);
+	s32 (*ext)(void *handle, void *values);
+	struct device *dev;
+};
+
+void *cyttsp_core_init(struct cyttsp_bus_ops *bus_ops, struct device *dev);
+
+void cyttsp_core_release(void *handle);
+#ifdef CONFIG_PM
+int cyttsp_resume(void *handle);
+int cyttsp_suspend(void *handle);
+#endif
+
+#endif /* __CYTTSP_CORE_H__ */
diff --git a/include/linux/input/cyttsp.h b/include/linux/input/cyttsp.h
new file mode 100644
index 0000000..3907bfc
--- /dev/null
+++ b/include/linux/input/cyttsp.h
@@ -0,0 +1,68 @@
+/*
+ * Header file for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com (kev@cypress.com)
+ *
+ */
+#ifndef _CYTTSP_H_
+#define _CYTTSP_H_
+
+#define CY_SPI_NAME "cyttsp-spi"
+#define CY_I2C_NAME "cyttsp-i2c"
+/* Active Power state scanning/processing refresh interval */
+#define CY_ACT_INTRVL_DFLT 0x00 /* ms */
+/* touch timeout for the Active power */
+#define CY_TCH_TMOUT_DFLT 0xFF /* ms */
+/* Low Power state scanning/processing refresh interval */
+#define CY_LP_INTRVL_DFLT 0x0A /* ms */
+/* Active distance in pixels for a gesture to be reported */
+#define CY_ACT_DIST_DFLT 0xF8 /* pixels */
+
+enum cyttsp_powerstate {
+	CY_IDLE_STATE,
+	CY_ACTIVE_STATE,
+	CY_LOW_PWR_STATE,
+	CY_SLEEP_STATE,
+	CY_BL_STATE,
+	CY_INVALID_STATE	/* always last in the list */
+};
+
+struct cyttsp_platform_data {
+	u32 maxx;
+	u32 maxy;
+	bool use_hndshk;
+	bool use_sleep;
+	u8 act_dist;	/* Active distance */
+	u8 act_intrvl;  /* Active refresh interval; ms */
+	u8 tch_tmout;   /* Active touch timeout; ms */
+	u8 lp_intrvl;   /* Low power refresh interval; ms */
+	int (*wakeup)(void);
+	int (*init)(void);
+	void (*exit)(void);
+	char *name;
+	s16 irq_gpio;
+	u8 *bl_keys;
+};
+
+#endif /* _CYTTSP_H_ */
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v4 2/3] 2/3 i2c: Cypress TTSP G3 I2C Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (11 preceding siblings ...)
  2011-01-05  0:54 ` [v4 1/3] 1/3 Touchscreen: Cypress TTSP G3 Core Driver Kevin McNeely
@ 2011-01-05  0:54 ` Kevin McNeely
  2011-01-05  0:54 ` [v4 3/3] 3/3 spi: Cypress TTSP G3 SPI " Kevin McNeely
  13 siblings, 0 replies; 70+ messages in thread
From: Kevin McNeely @ 2011-01-05  0:54 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Mike Frysinger, Henrik Rydberg,
	Alan Cox, linux-input, linux-kernel

Cypress TTSP Gen3 I2C Device Driver.
Provides i2c communications modules for the
Cypress TTSP Gen3 MTDEV Core Driver.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
Changes since v3:
- Corrected pointers passed in suspend and resume to cyttsp_i2c->ttsp_client
- replace EIO with EINVAL

 drivers/input/touchscreen/Kconfig      |   12 ++
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/cyttsp_i2c.c |  188 ++++++++++++++++++++++++++++++++
 3 files changed, 201 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_i2c.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index c3240b8..b1d20af8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -129,6 +129,18 @@ config TOUCHSCREEN_CYTTSP_CORE
 	help
 	  Always activated for Cypress TTSP touchscreen
 
+config TOUCHSCREEN_CYTTSP_I2C
+	tristate "Cypress TTSP i2c touchscreen"
+	depends on I2C && TOUCHSCREEN_CYTTSP_CORE
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your system with an I2C interface.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp-i2c.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index b6f1ba8..88ee091 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)    += cyttsp_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
new file mode 100644
index 0000000..d79c6a7
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -0,0 +1,188 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#define CY_I2C_DATA_SIZE  128
+
+struct cyttsp_i2c {
+	struct cyttsp_bus_ops ops;
+	struct i2c_client *client;
+	void *ttsp_client;
+	u8 wr_buf[CY_I2C_DATA_SIZE];
+};
+
+static s32 ttsp_i2c_read_block_data(void *handle, u8 addr,
+	u8 length, void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval = 0;
+
+	retval = i2c_master_send(ts->client, &addr, 1);
+	if (retval < 0)
+		return retval;
+
+	retval = i2c_master_recv(ts->client, values, length);
+
+	return (retval < 0) ? retval : 0;
+}
+
+static s32 ttsp_i2c_write_block_data(void *handle, u8 addr,
+	u8 length, const void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval;
+
+	ts->wr_buf[0] = addr;
+	memcpy(&ts->wr_buf[1], values, length);
+
+	retval = i2c_master_send(ts->client, ts->wr_buf, length+1);
+
+	return (retval < 0) ? retval : 0;
+}
+
+static s32 ttsp_i2c_tch_ext(void *handle, void *values)
+{
+	struct cyttsp_i2c *ts = container_of(handle, struct cyttsp_i2c, ops);
+	int retval = 0;
+
+	/*
+	 * TODO: Add custom touch extension handling code here
+	 * set: retval < 0 for any returned system errors,
+	 *	retval = 0 if normal touch handling is required,
+	 *	retval > 0 if normal touch handling is *not* required
+	 */
+	if (!ts || !values)
+		retval = -EINVAL;
+
+	return retval;
+}
+
+static int __devinit cyttsp_i2c_probe(struct i2c_client *client,
+	const struct i2c_device_id *id)
+{
+	struct cyttsp_i2c *ts;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		return -EIO;
+
+	/* allocate and clear memory */
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		dev_dbg(&client->dev, "%s: Error, kzalloc.\n", __func__);
+		return -ENOMEM;
+	}
+
+	/* register driver_data */
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	ts->ops.write = ttsp_i2c_write_block_data;
+	ts->ops.read = ttsp_i2c_read_block_data;
+	ts->ops.ext = ttsp_i2c_tch_ext;
+	ts->ops.dev = &client->dev;
+	ts->ops.dev->bus = &i2c_bus_type;
+
+	ts->ttsp_client = cyttsp_core_init(&ts->ops, &client->dev);
+	if (IS_ERR(ts->ttsp_client)) {
+		int retval = PTR_ERR(ts->ttsp_client);
+		kfree(ts);
+		return retval;
+	}
+
+	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
+
+	return 0;
+}
+
+
+/* registered in driver struct */
+static int __devexit cyttsp_i2c_remove(struct i2c_client *client)
+{
+	struct cyttsp_i2c *ts;
+
+	ts = i2c_get_clientdata(client);
+	cyttsp_core_release(ts->ttsp_client);
+	kfree(ts);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_i2c_suspend(struct i2c_client *client, pm_message_t message)
+{
+	struct cyttsp_i2c *ts = i2c_get_clientdata(client);
+
+	return cyttsp_suspend(ts->ttsp_client);
+}
+
+static int cyttsp_i2c_resume(struct i2c_client *client)
+{
+	struct cyttsp_i2c *ts = i2c_get_clientdata(client);
+
+	return cyttsp_resume(ts->ttsp_client);
+}
+#endif
+
+static const struct i2c_device_id cyttsp_i2c_id[] = {
+	{ CY_I2C_NAME, 0 },  { }
+};
+
+static struct i2c_driver cyttsp_i2c_driver = {
+	.driver = {
+		.name = CY_I2C_NAME,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_i2c_probe,
+	.remove = __devexit_p(cyttsp_i2c_remove),
+	.id_table = cyttsp_i2c_id,
+#ifdef CONFIG_PM
+	.suspend = cyttsp_i2c_suspend,
+	.resume = cyttsp_i2c_resume,
+#endif
+};
+
+static int __init cyttsp_i2c_init(void)
+{
+	return i2c_add_driver(&cyttsp_i2c_driver);
+}
+
+static void __exit cyttsp_i2c_exit(void)
+{
+	return i2c_del_driver(&cyttsp_i2c_driver);
+}
+
+module_init(cyttsp_i2c_init);
+module_exit(cyttsp_i2c_exit);
+
+MODULE_ALIAS("i2c:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
+MODULE_AUTHOR("Cypress");
+MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* [v4 3/3] 3/3 spi: Cypress TTSP G3 SPI Device Driver
       [not found] <Kevin McNeely <kev@cypress.com>
                   ` (12 preceding siblings ...)
  2011-01-05  0:54 ` [v4 2/3] 2/3 i2c: Cypress TTSP G3 I2C Device Driver Kevin McNeely
@ 2011-01-05  0:54 ` Kevin McNeely
  2011-01-12 18:45   ` Dmitry Torokhov
  13 siblings, 1 reply; 70+ messages in thread
From: Kevin McNeely @ 2011-01-05  0:54 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: David Brown, Trilok Soni, Kevin McNeely, Dmitry Torokhov,
	Samuel Ortiz, Eric Miao, Mike Frysinger, Henrik Rydberg,
	Alan Cox, linux-input, linux-kernel

Cypress TTSP Gen3 SPI Device Driver.
Provides spi communications modules for the
Cypress TTSP Gen3 MTDEV Core Driver.

Signed-off-by: Kevin McNeely <kev@cypress.com>
---
Changes since v3:
- Corrected pointers passed in suspend and resume to cyttsp_spi->ttsp_client
- replace EIO with EINVAL

 drivers/input/touchscreen/Kconfig      |   12 ++
 drivers/input/touchscreen/Makefile     |    1 +
 drivers/input/touchscreen/cyttsp_spi.c |  318 ++++++++++++++++++++++++++++++++
 3 files changed, 331 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_spi.c

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b1d20af8..77239db 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -141,6 +141,18 @@ config TOUCHSCREEN_CYTTSP_I2C
 	  To compile this driver as a module, choose M here: the
 	  module will be called cyttsp-i2c.
 
+config TOUCHSCREEN_CYTTSP_SPI
+	tristate "Cypress TTSP spi touchscreen"
+	depends on SPI_MASTER && TOUCHSCREEN_CYTTSP_CORE
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen
+	  connected to your  with an SPI interface.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp-spi.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 88ee091..6c6d4bb 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
 obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C)    += cyttsp_i2c.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI)    += cyttsp_spi.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_spi.c b/drivers/input/touchscreen/cyttsp_spi.c
new file mode 100644
index 0000000..108c37f
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_spi.c
@@ -0,0 +1,318 @@
+/*
+ * Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#define CY_SPI_WR_OP      0x00 /* r/~w */
+#define CY_SPI_RD_OP      0x01
+#define CY_SPI_CMD_BYTES  4
+#define CY_SPI_SYNC_BYTE  2
+#define CY_SPI_SYNC_ACK1  0x62 /* from protocol v.2 */
+#define CY_SPI_SYNC_ACK2  0x9D /* from protocol v.2 */
+#define CY_SPI_DATA_SIZE  128
+#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
+#define CY_SPI_BITS_PER_WORD 8
+
+struct cyttsp_spi {
+	struct cyttsp_bus_ops ops;
+	struct spi_device *spi_client;
+	void *ttsp_client;
+	u8 wr_buf[CY_SPI_DATA_BUF_SIZE];
+	u8 rd_buf[CY_SPI_DATA_BUF_SIZE];
+};
+
+static void spi_complete(void *arg)
+{
+	complete(arg);
+}
+
+static int spi_sync_tmo(struct cyttsp_spi *ts, struct spi_message *message)
+{
+	DECLARE_COMPLETION_ONSTACK(done);
+	int status;
+
+	message->complete = spi_complete;
+	message->context = &done;
+	status = spi_async(ts->spi_client, message);
+	if (status == 0) {
+		int ret = wait_for_completion_interruptible_timeout(&done, HZ);
+		if (!ret) {
+			dev_dbg(ts->ops.dev, "%s: timeout\n", __func__);
+			status = -EIO;
+		} else
+			status = message->status;
+	}
+	message->context = NULL;
+	return status;
+}
+
+static int cyttsp_spi_xfer_(u8 op, struct cyttsp_spi *ts,
+			    u8 reg, u8 *buf, int length)
+{
+	struct spi_message msg;
+	struct spi_transfer xfer[2];
+	u8 *wr_buf = ts->wr_buf;
+	u8 *rd_buf = ts->rd_buf;
+	int retval;
+
+	if (length > CY_SPI_DATA_SIZE) {
+		dev_dbg(ts->ops.dev, "%s: length %d is too big.\n",
+			__func__, length);
+		return -EINVAL;
+	}
+
+	memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
+	memset(rd_buf, 0, CY_SPI_DATA_BUF_SIZE);
+
+	wr_buf[0] = 0x00; /* header byte 0 */
+	wr_buf[1] = 0xFF; /* header byte 1 */
+	wr_buf[2] = reg;  /* reg index */
+	wr_buf[3] = op;   /* r/~w */
+	if (op == CY_SPI_WR_OP)
+		memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
+
+	memset((void *)xfer, 0, sizeof(xfer));
+	spi_message_init(&msg);
+	xfer[0].tx_buf = wr_buf;
+	xfer[0].rx_buf = rd_buf;
+	if (op == CY_SPI_WR_OP) {
+		xfer[0].len = length + CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+	} else if (op == CY_SPI_RD_OP) {
+		xfer[0].len = CY_SPI_CMD_BYTES;
+		spi_message_add_tail(&xfer[0], &msg);
+
+		xfer[1].rx_buf = buf;
+		xfer[1].len = length;
+		spi_message_add_tail(&xfer[1], &msg);
+	}
+
+	retval = spi_sync_tmo(ts, &msg);
+	if (retval < 0) {
+		dev_dbg(ts->ops.dev, "%s: spi sync error %d, len=%d, op=%d\n",
+			__func__, retval, xfer[1].len, op);
+		retval = 0;
+	}
+
+	if (op == CY_SPI_RD_OP) {
+		if ((rd_buf[CY_SPI_SYNC_BYTE] == CY_SPI_SYNC_ACK1) &&
+			(rd_buf[CY_SPI_SYNC_BYTE+1] == CY_SPI_SYNC_ACK2))
+			retval = 0;
+		else {
+			int i;
+			for (i = 0; i < (CY_SPI_CMD_BYTES); i++)
+				dev_dbg(ts->ops.dev,
+					"%s: test rd_buf[%d]:0x%02x\n",
+					__func__, i, rd_buf[i]);
+			for (i = 0; i < (length); i++)
+				dev_dbg(ts->ops.dev,
+					"%s: test buf[%d]:0x%02x\n",
+					__func__, i, buf[i]);
+			retval = 1;
+		}
+	}
+	return retval;
+}
+
+static int cyttsp_spi_xfer(u8 op, struct cyttsp_spi *ts,
+			    u8 reg, u8 *buf, int length)
+{
+	int tries;
+	int retval;
+
+	if (op == CY_SPI_RD_OP) {
+		for (tries = CY_NUM_RETRY; tries; tries--) {
+			retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+			if (retval == 0)
+				break;
+			else
+				msleep(20);
+		}
+	} else {
+		retval = cyttsp_spi_xfer_(op, ts, reg, buf, length);
+	}
+
+	return retval;
+}
+
+static s32 ttsp_spi_read_block_data(void *handle, u8 addr,
+				    u8 length, void *data)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval;
+
+	retval = cyttsp_spi_xfer(CY_SPI_RD_OP, ts, addr, data, length);
+	if (retval < 0)
+		dev_dbg(ts->ops.dev,  "%s: ttsp_spi_read_block_data failed\n",
+			__func__);
+
+	/*
+	 * Do not print the above error if the data sync bytes were not found.
+	 * This is a normal condition for the bootloader loader startup and need
+	 * to retry until data sync bytes are found.
+	 */
+	if (retval > 0)
+		retval = -1;	/* now signal fail; so retry can be done */
+
+	return retval;
+}
+
+static s32 ttsp_spi_write_block_data(void *handle, u8 addr,
+				     u8 length, const void *data)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval;
+
+	retval = cyttsp_spi_xfer(CY_SPI_WR_OP, ts, addr, (void *)data, length);
+	if (retval < 0)
+		dev_dbg(ts->ops.dev, "%s: ttsp_spi_write_block_data failed\n",
+			__func__);
+
+	if (retval == -EIO)
+		return 0;
+	else
+		return retval;
+}
+
+static s32 ttsp_spi_tch_ext(void *handle, void *values)
+{
+	struct cyttsp_spi *ts = container_of(handle, struct cyttsp_spi, ops);
+	int retval = 0;
+
+	/*
+	 * TODO: Add custom touch extension handling code here
+	 * set: retval < 0 for any returned system errors,
+	 *	retval = 0 if normal touch handling is required,
+	 *	retval > 0 if normal touch handling is *not* required
+	 */
+
+	if (!ts || !values)
+		retval = -EINVAL;
+
+	return retval;
+}
+
+static int __devinit cyttsp_spi_probe(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts;
+	int retval;
+
+	/* Set up SPI*/
+	spi->bits_per_word = CY_SPI_BITS_PER_WORD;
+	spi->mode = SPI_MODE_0;
+	retval = spi_setup(spi);
+	if (retval < 0) {
+		dev_dbg(&spi->dev, "%s: SPI setup error %d\n",
+			__func__, retval);
+		return retval;
+	}
+
+	ts = kzalloc(sizeof(*ts), GFP_KERNEL);
+	if (!ts) {
+		dev_dbg(&spi->dev, "%s: Error, kzalloc\n", __func__);
+		return -ENOMEM;
+	}
+
+	ts->spi_client = spi;
+	dev_set_drvdata(&spi->dev, ts);
+	ts->ops.write = ttsp_spi_write_block_data;
+	ts->ops.read = ttsp_spi_read_block_data;
+	ts->ops.ext = ttsp_spi_tch_ext;
+	ts->ops.dev = &spi->dev;
+
+	ts->ttsp_client = cyttsp_core_init(&ts->ops, &spi->dev);
+	if (IS_ERR(ts->ttsp_client)) {
+		int retval = PTR_ERR(ts->ttsp_client);
+		kfree(ts);
+		return retval;
+	}
+
+	dev_dbg(ts->ops.dev, "%s: Registration complete\n", __func__);
+
+	return 0;
+}
+
+static int __devexit cyttsp_spi_remove(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev);
+
+	cyttsp_core_release(ts->ttsp_client);
+	kfree(ts);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int cyttsp_spi_suspend(struct spi_device *spi, pm_message_t message)
+{
+	struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev);
+
+	return cyttsp_suspend(ts->ttsp_client);
+}
+
+static int cyttsp_spi_resume(struct spi_device *spi)
+{
+	struct cyttsp_spi *ts = dev_get_drvdata(&spi->dev);
+
+	return cyttsp_resume(ts->ttsp_client);
+}
+#endif
+
+static struct spi_driver cyttsp_spi_driver = {
+	.driver = {
+		.name = CY_SPI_NAME,
+		.bus = &spi_bus_type,
+		.owner = THIS_MODULE,
+	},
+	.probe = cyttsp_spi_probe,
+	.remove = __devexit_p(cyttsp_spi_remove),
+#ifdef CONFIG_PM
+	.suspend = cyttsp_spi_suspend,
+	.resume = cyttsp_spi_resume,
+#endif
+};
+
+static int __init cyttsp_spi_init(void)
+{
+	return spi_register_driver(&cyttsp_spi_driver);
+}
+module_init(cyttsp_spi_init);
+
+static void __exit cyttsp_spi_exit(void)
+{
+	spi_unregister_driver(&cyttsp_spi_driver);
+}
+module_exit(cyttsp_spi_exit);
+
+MODULE_ALIAS("spi:cyttsp");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
+MODULE_AUTHOR("Cypress");
+
-- 
1.7.2.1


---------------------------------------------------------------
This message and any attachments may contain Cypress (or its
subsidiaries) confidential information. If it has been received
in error, please advise the sender and immediately delete this
message.
---------------------------------------------------------------


^ permalink raw reply	[flat|nested] 70+ messages in thread

* Re: [v4 1/3] 1/3 Touchscreen: Cypress TTSP G3 Core Driver
  2011-01-05  0:54 ` [v4 1/3] 1/3 Touchscreen: Cypress TTSP G3 Core Driver Kevin McNeely
@ 2011-01-05  8:59   ` Henrik Rydberg
  2011-01-05 17:07     ` Kevin McNeely
  0 siblings, 1 reply; 70+ messages in thread
From: Henrik Rydberg @ 2011-01-05  8:59 UTC (permalink / raw)
  To: Kevin McNeely
  Cc: Dmitry Torokhov, David Brown, Trilok Soni, Samuel Ortiz,
	Eric Miao, Mike Frysinger, Alan Cox, linux-input, linux-kernel

> Cypress TTSP Gen3 Core Driver.
> Core Driver includes platform data definition file,
> core driver definition file, and core touchscreen
> touch handling of device data. Generates
> multi-touch input events.
> 
> Signed-off-by: Kevin McNeely <kev@cypress.com>
> ---

Hi Kevin,

> @@ -124,6 +124,11 @@ config TOUCHSCREEN_CY8CTMG110
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called cy8ctmg110_ts.
>  
> +config TOUCHSCREEN_CYTTSP_CORE
> +	tristate "Cypress TTSP touchscreen core"
> +	help
> +	  Always activated for Cypress TTSP touchscreen
> +

This one needs a bit of elaboration, see patch at the end.

> +static const u8 bl_command[] = {
> +	0x00,			/* file offset */
> +	0xFF,			/* command */
> +	0xA5,			/* exit bootloader command */
> +	0, 1, 2, 3, 4, 5, 6, 7	/* default keys */
> +};

Nice.

> +/* process current touches */
> +#define CY_MAX_TCH	2
> +static int cyttsp_xy_worker(struct cyttsp *ts)
> +{
> +	u8 num_cur_tch;
> +	u16 x[CY_MAX_TCH];
> +	u16 y[CY_MAX_TCH];
> +	u8 z[CY_MAX_TCH];
> +	bool t[CY_MAX_TCH];
> +	int i;

This became more complicated than the previous patch...

> +	/* send touches */
> +	if (!num_cur_tch)
> +		/* terminate previous active touch */
> +		input_mt_sync(ts->input);
> +	else {
> +		/* get touch 1 */
> +		/*
> +		 * If there is only one current active touch,
> +		 * it will be reported in the touch 1 regardless
> +		 * if it was reported in the touch 2 previously
> +		 */

This statement says that t[] is not needed - the idea was to simply
set all values in x[], y[] and z[], and then loop over the num_cur_tch
touches.

> +		x[0] = (ts->xy_data.tch1_xhi << 8) + ts->xy_data.tch1_xlo;
> +		y[0] = (ts->xy_data.tch1_yhi << 8) + ts->xy_data.tch1_ylo;
> +		z[0] = ts->xy_data.tch1_z;
> +		t[0] = true;
> +
> +		/* get touch 2 */
> +		if (num_cur_tch == CY_MAX_TCH) {
> +			x[1] = (ts->xy_data.tch2_xhi << 8) +
> +				ts->xy_data.tch2_xlo;
> +			y[1] = (ts->xy_data.tch2_yhi << 8) +
> +				ts->xy_data.tch2_ylo;
> +			z[1] = ts->xy_data.tch2_z;
> +			t[1] = true;
> +		}
> +
> +		for (i = 0; i < CY_MAX_TCH; i++) {

Using num_cur_tch here,

> +			if (t[i]) {

and removing t[i] here makes the comment above obvious.

> +				input_report_abs(ts->input,
> +					ABS_MT_POSITION_X, x[i]);
> +				input_report_abs(ts->input,
> +					ABS_MT_POSITION_Y, y[i]);
> +				input_report_abs(ts->input,
> +					ABS_MT_TOUCH_MAJOR, z[i]);
> +				input_mt_sync(ts->input);
> +			}
> +		}
> +	}
> +
> +	input_sync(ts->input);
> +
> +	return 0;
> +}

All in all, it seems we have yet to arrive at the most comfortable
solution, in particular if there is a plan to magically enable more
contacts.  Looking again at the data from the device, perhaps one can
simplify things a bit more.  How about the patch below, does that
still work for you?

Thanks,
Henrik
---

>From f254daabcbd891bbcc3ccc4b923cf0a848b5f913 Mon Sep 17 00:00:00 2001
From: Kevin McNeely <kev@cypress.com>
Date: Wed, 5 Jan 2011 09:34:42 +0100
Subject: [PATCH] Input: Cypress TTSP G3 Core Driver

Core Driver includes platform data definition file,
core driver definition file, and core touchscreen
touch handling of device data. Generates
multi-touch input events.

[rydberg@euromail.se: minor cleanup]
Signed-off-by: Kevin McNeely <kev@cypress.com>
---
 drivers/input/touchscreen/Kconfig       |    5 +
 drivers/input/touchscreen/Makefile      |    1 +
 drivers/input/touchscreen/cyttsp_core.c |  758 +++++++++++++++++++++++++++++++
 drivers/input/touchscreen/cyttsp_core.h |   55 +++
 include/linux/input/cyttsp.h            |   68 +++
 5 files changed, 887 insertions(+), 0 deletions(-)
 create mode 100644 drivers/input/touchscreen/cyttsp_core.c
 create mode 100644 drivers/input/touchscreen/cyttsp_core.h
 create mode 100644 include/linux/input/cyttsp.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 06ea8da..c3240b8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -124,6 +124,17 @@ config TOUCHSCREEN_CY8CTMG110
 	  To compile this driver as a module, choose M here: the
 	  module will be called cy8ctmg110_ts.
 
+config TOUCHSCREEN_CYTTSP_CORE
+	tristate "Cypress TTSP touchscreen core"
+	help
+	  Say Y here if you have a Cypress TTSP touchscreen and want
+	  built-in support for it.
+
+	  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cyttsp_core.
+
 config TOUCHSCREEN_DA9034
 	tristate "Touchscreen support for Dialog Semiconductor DA9034"
 	depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 7cc1b4f..b6f1ba8 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC)	+= atmel_tsadcc.o
 obj-$(CONFIG_TOUCHSCREEN_BITSY)		+= h3600_ts_input.o
 obj-$(CONFIG_TOUCHSCREEN_BU21013)       += bu21013_ts.o
 obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110)	+= cy8ctmg110_ts.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE)   += cyttsp_core.o
 obj-$(CONFIG_TOUCHSCREEN_DA9034)	+= da9034-ts.o
 obj-$(CONFIG_TOUCHSCREEN_DYNAPRO)	+= dynapro.o
 obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE)	+= hampshire.o
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
new file mode 100644
index 0000000..6971533
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -0,0 +1,757 @@
+/*
+ * Core Source for:
+ * Cypress TrueTouch(TM) Standard Product (TTSP) touchscreen drivers.
+ * For use with Cypress Txx3xx parts.
+ * Supported parts include:
+ * CY8CTST341
+ * CY8CTMA340
+ *
+ * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, and only version 2, as published by the
+ * Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contact Cypress Semiconductor at www.cypress.com <kev@cypress.com>
+ *
+ */
+
+#include "cyttsp_core.h"
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+/* Bootloader number of command keys */
+#define CY_NUM_BL_KEYS    8
+
+/* helpers */
+#define GET_NUM_TOUCHES(x)          ((x) & 0x0F)
+#define IS_LARGE_AREA(x)            (((x) & 0x10) >> 4)
+#define IS_BAD_PKT(x)               ((x) & 0x20)
+#define IS_VALID_APP(x)             ((x) & 0x01)
+#define IS_OPERATIONAL_ERR(x)       ((x) & 0x3F)
+#define GET_HSTMODE(reg)            ((reg & 0x70) >> 4)
+#define GET_BOOTLOADERMODE(reg)     ((reg & 0x10) >> 4)
+
+#define CY_REG_BASE                 0x00
+#define CY_REG_ACT_DIST             0x1E
+#define CY_REG_ACT_INTRVL           0x1D
+#define CY_REG_TCH_TMOUT            (CY_REG_ACT_INTRVL+1)
+#define CY_REG_LP_INTRVL            (CY_REG_TCH_TMOUT+1)
+#define CY_MAXZ                     255
+#define CY_DELAY_DFLT               20 /* ms */
+#define CY_DELAY_MAX                (500/CY_DELAY_DFLT) /* half second */
+#define CY_ACT_DIST_DFLT            0xF8
+#define CY_HNDSHK_BIT               0x80
+/* device mode bits */
+#define CY_OPERATE_MODE             0x00
+#define CY_SYSINFO_MODE             0x10
+/* power mode select bits */
+#define CY_SOFT_RESET_MODE          0x01 /* return to Bootloader mode */
+#define CY_DEEP_SLEEP_MODE          0x02
+#define CY_LOW_POWER_MODE           0x04
+
+struct cyttsp_tch {
+	__be16 x, y;
+	u8 z, unused;
+} __attribute__((packed));
+
+/* TrueTouch Standard Product Gen3 interface definition */
+struct cyttsp_xydata {
+	u8 hst_mode;
+	u8 tt_mode;
+	u8 tt_stat;
+	struct cyttsp_tch tch[2];
+	u8 unused_grp[12];
+	u8 tt_undef[3];
+	u8 act_dist;
+	u8 tt_reserved;
+} __attribute__((packed));
+
+/* TTSP System Information interface definition */
+struct cyttsp_sysinfo_data {
+	u8 hst_mode;
+	u8 mfg_cmd;
+	u8 mfg_stat;
+	u8 cid[3];
+	u8 tt_undef1;
+	u8 uid[8];
+	u8 bl_verh;
+	u8 bl_verl;
+	u8 tts_verh;
+	u8 tts_verl;
+	u8 app_idh;
+	u8 app_idl;
+	u8 app_verh;
+	u8 app_verl;
+	u8 tt_undef[5];
+	u8 scn_typ;
+	u8 act_intrvl;
+	u8 tch_tmout;
+	u8 lp_intrvl;
+};
+
+/* TTSP Bootloader Register Map interface definition */
+#define CY_BL_CHKSUM_OK 0x01
+struct cyttsp_bootloader_data {
+	u8 bl_file;
+	u8 bl_status;
+	u8 bl_error;
+	u8 blver_hi;
+	u8 blver_lo;
+	u8 bld_blver_hi;
+	u8 bld_blver_lo;
+	u8 ttspver_hi;
+	u8 ttspver_lo;
+	u8 appid_hi;
+	u8 appid_lo;
+	u8 appver_hi;
+	u8 appver_lo;
+	u8 cid_0;
+	u8 cid_1;
+	u8 cid_2;
+};
+
+struct cyttsp {
+	struct device *dev;
+	int irq;
+	struct input_dev *input;
+	char phys[32];
+	const struct bus_type *bus_type;
+	const struct cyttsp_platform_data *platform_data;
+	struct cyttsp_bus_ops *bus_ops;
+	struct cyttsp_bootloader_data bl_data;
+	struct cyttsp_sysinfo_data sysinfo_data;
+	struct completion bl_ready;
+	enum cyttsp_powerstate power_state;
+};
+
+static const u8 bl_command[] = {
+	0x00,			/* file offset */
+	0xFF,			/* command */
+	0xA5,			/* exit bootloader command */
+	0, 1, 2, 3, 4, 5, 6, 7	/* default keys */
+};
+
+static int ttsp_read_block_data(struct cyttsp *ts, u8 command,
+	u8 length, void *buf)
+{
+	i