lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Tue,  9 Nov 2010 10:25:17 -0800
From:	Kevin McNeely <kev@...ress.com>
To:	Dmitry Torokhov <dmitry.torokhov@...il.com>
Cc:	David Brown <davidb@...eaurora.org>,
	Trilok Soni <tsoni@...eaurora.org>,
	Kevin McNeely <kev@...ress.com>,
	Dmitry Torokhov <dmitry.torokhov@...il.com>,
	Henrik Rydberg <rydberg@...omail.se>,
	Samuel Ortiz <sameo@...ux.intel.com>,
	Eric Miao <eric.y.miao@...il.com>,
	Simtec Linux Team <linux@...tec.co.uk>,
	Luotao Fu <l.fu@...gutronix.de>, linux-input@...r.kernel.org,
	linux-kernel@...r.kernel.org
Subject: [PATCH] touchscreen: Cypress TTSP G3 MTDEV Core Driver

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@...ress.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@...ress.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@...ress.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@...ress.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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ