linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Ferruh Yigit <fery@cypress.com>
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Kevin McNeely <kev@cypress.com>, Ferruh YIGIT <fery@cypress.com>,
	Javier Martinez Canillas <javier@dowhile0.org>,
	Henrik Rydberg <rydberg@euromail.se>,
	Shawn Landden <shawnlandden@gmail.com>,
	Ashish Jangam <ashish.jangam@kpitcummins.com>,
	Olivier Sobrie <olivier@sobrie.be>,
	linux-input@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 3/4] Input: cyttsp4 - MultiTouch driver for Cypress TMA4XX touchscreen devices
Date: Tue, 7 Aug 2012 16:10:25 +0300	[thread overview]
Message-ID: <1344345032-30537-1-git-send-email-fery@cypress.com> (raw)
In-Reply-To: <Ferruh Yigit <fery@cypress.com>

From: Ferruh YIGIT <fery@cypress.com>

Cypress TrueTouch(tm) Standard Product controllers, Generetion4
devices, MutliTouch driver.

Subscribes to core driver and converts touch information to OS specific
touch events.

This module is supports multi-touch protocol type B reports.

Signed-off-by: Ferruh YIGIT <fery@cypress.com>
---
 drivers/input/touchscreen/Kconfig             |    9 +
 drivers/input/touchscreen/Makefile            |    8 +
 drivers/input/touchscreen/cyttsp4_mt_common.c |  612 +++++++++++++++++++++++++
 drivers/input/touchscreen/cyttsp4_mt_common.h |   76 +++
 drivers/input/touchscreen/cyttsp4_mtb.c       |  107 +++++
 include/linux/cyttsp4_mt.h                    |   72 +++
 6 files changed, 884 insertions(+)
 create mode 100644 drivers/input/touchscreen/cyttsp4_mt_common.c
 create mode 100644 drivers/input/touchscreen/cyttsp4_mt_common.h
 create mode 100644 drivers/input/touchscreen/cyttsp4_mtb.c
 create mode 100644 include/linux/cyttsp4_mt.h

diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6fa7278..57a38f8 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -192,6 +192,7 @@ config TOUCHSCREEN_CYPRESS_CYTTSP4
        tristate "Cypress TrueTouch Gen4 Touchscreen Driver"
        default m
        select CYPRESS_CYTTSP4_BUS
+       select TOUCHSCREEN_CYPRESS_CYTTSP4_MT_B
        help
          Core driver for Cypress TrueTouch(tm) Standard Product
          Geneartion4 touchscreen controllers.
@@ -222,6 +223,14 @@ config TOUCHSCREEN_CYPRESS_CYTTSP4_VDEBUG

          Say Y here to enable verbose debug output.

+config TOUCHSCREEN_CYPRESS_CYTTSP4_MT_B
+       tristate "Cypress TrueTouch Gen4 MultiTouch Protocol B"
+       depends on TOUCHSCREEN_CYPRESS_CYTTSP4
+       default m
+       help
+         Cypress TrueTouch(tm) Standard Product Generation4
+         MutliTouch Protocol B support.
+
 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 d12965b..8feae16 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -75,12 +75,20 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900)   += w90p910_ts.o
 obj-$(CONFIG_TOUCHSCREEN_TPS6507X)     += tps6507x-ts.o
 obj-$(CONFIG_CYPRESS_CYTTSP4_BUS) += cyttsp4_bus.o
 obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP4)      += cyttsp4_core.o
+obj-$(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP4_MT_B) += cyttsp4_mt_b.o
+cyttsp4_mt_b-y := cyttsp4_mtb.o cyttsp4_mt_common.o
 ifeq ($(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP4_DEBUG),y)
 CFLAGS_cyttsp4_core.o += -DDEBUG
 CFLAGS_cyttsp4_bus.o += -DDEBUG
+CFLAGS_cyttsp4_mtb.o += -DDEBUG
+CFLAGS_cyttsp4_mt_b.o += -DDEBUG
+CFLAGS_cyttsp4_mt_common.o += -DDEBUG
 endif

 ifeq ($(CONFIG_TOUCHSCREEN_CYPRESS_CYTTSP4_VDEBUG),y)
 CFLAGS_cyttsp4_core.o += -DVERBOSE_DEBUG
 CFLAGS_cyttsp4_bus.o += -DVERBOSE_DEBUG
+CFLAGS_cyttsp4_mtb.o += -DVERBOSE_DEBUG
+CFLAGS_cyttsp4_mt_b.o += -DVERBOSE_DEBUG
+CFLAGS_cyttsp4_mt_common.o += -DVERBOSE_DEBUG
 endif
diff --git a/drivers/input/touchscreen/cyttsp4_mt_common.c b/drivers/input/touchscreen/cyttsp4_mt_common.c
new file mode 100644
index 0000000..e512f9c
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_mt_common.c
@@ -0,0 +1,612 @@
+/*
+ * cyttsp4_mt_common.c
+ * Cypress TrueTouch(TM) Standard Product V4 Multi-touch module.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * 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 <ttdrivers@cypress.com>
+ *
+ */
+
+#include "cyttsp4_mt_common.h"
+
+static void cyttsp4_lift_all(struct cyttsp4_mt_data *md)
+{
+       if (md->num_prv_tch != 0) {
+               if (md->mt_function.report_slot_liftoff)
+                       md->mt_function.report_slot_liftoff(md);
+               /* ICS Lift off button release signal and empty mt */
+               if (md->prv_tch_type != CY_OBJ_HOVER)
+                       input_report_key(md->input, BTN_TOUCH, CY_BTN_RELEASED);
+               input_sync(md->input);
+               md->num_prv_tch = 0;
+       }
+}
+
+static void cyttsp4_get_touch_axis(struct cyttsp4_mt_data *md,
+       int *axis, int size, int max, u8 *xy_data, int bofs)
+{
+       int nbyte;
+       int next;
+
+       for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
+               dev_vdbg(&md->ttsp->dev,
+                       "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
+                       " xy_data[%d]=%02X(%d) bofs=%d\n",
+                       __func__, *axis, *axis, size, max, xy_data, next,
+                       xy_data[next], xy_data[next], bofs);
+               *axis = (*axis * 256) + (xy_data[next] >> bofs);
+               next++;
+       }
+
+       *axis &= max - 1;
+
+       dev_vdbg(&md->ttsp->dev,
+               "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
+               " xy_data[%d]=%02X(%d)\n",
+               __func__, *axis, *axis, size, max, xy_data, next,
+               xy_data[next], xy_data[next]);
+}
+
+static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
+       struct cyttsp4_touch *touch, u8 *xy_data)
+{
+       struct device *dev = &md->ttsp->dev;
+       struct cyttsp4_sysinfo *si = md->si;
+       enum cyttsp4_tch_abs abs;
+       int tmp;
+       bool flipped;
+
+       for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
+               cyttsp4_get_touch_axis(md, &touch->abs[abs],
+                       si->si_ofs.tch_abs[abs].size,
+                       si->si_ofs.tch_abs[abs].max,
+                       xy_data + si->si_ofs.tch_abs[abs].ofs,
+                       si->si_ofs.tch_abs[abs].bofs);
+               dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
+                       cyttsp4_tch_abs_string[abs],
+                       touch->abs[abs], touch->abs[abs]);
+       }
+
+       if (md->pdata->flags & CY_FLAG_FLIP) {
+               tmp = touch->abs[CY_TCH_X];
+               touch->abs[CY_TCH_X] = touch->abs[CY_TCH_Y];
+               touch->abs[CY_TCH_Y] = tmp;
+               flipped = true;
+       } else
+               flipped = false;
+
+       if (md->pdata->flags & CY_FLAG_INV_X) {
+               if (flipped)
+                       touch->abs[CY_TCH_X] = md->si->si_ofs.max_y -
+                               touch->abs[CY_TCH_X];
+               else
+                       touch->abs[CY_TCH_X] = md->si->si_ofs.max_x -
+                               touch->abs[CY_TCH_X];
+       }
+       if (md->pdata->flags & CY_FLAG_INV_Y) {
+               if (flipped)
+                       touch->abs[CY_TCH_Y] = md->si->si_ofs.max_x -
+                               touch->abs[CY_TCH_Y];
+               else
+                       touch->abs[CY_TCH_Y] = md->si->si_ofs.max_y -
+                               touch->abs[CY_TCH_Y];
+       }
+
+       dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
+               __func__, flipped ? "true" : "false",
+               md->pdata->flags & CY_FLAG_INV_X ? "true" : "false",
+               md->pdata->flags & CY_FLAG_INV_Y ? "true" : "false",
+               touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
+               touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
+}
+
+static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch)
+{
+       struct device *dev = &md->ttsp->dev;
+       struct cyttsp4_sysinfo *si = md->si;
+       struct cyttsp4_touch tch;
+       int sig;
+       int i, j, t = 0;
+       int ids[max(CY_TMA1036_MAX_TCH + 1,
+               CY_TMA4XX_MAX_TCH + 1)]; /* add one for hover */
+       int mt_sync_count = 0;
+
+       memset(ids, 0, (si->si_ofs.max_tchs + 1) * sizeof(int));
+       memset(&tch, 0, sizeof(struct cyttsp4_touch));
+       for (i = 0; i < num_cur_tch; i++) {
+               cyttsp4_get_touch(md, &tch, si->xy_data +
+                       (i * si->si_ofs.tch_rec_size));
+               if ((tch.abs[CY_TCH_T] < md->pdata->frmwrk->abs
+                       [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]) ||
+                       (tch.abs[CY_TCH_T] > md->pdata->frmwrk->abs
+                       [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MAX_OST])) {
+                       dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
+                               __func__, i, tch.abs[CY_TCH_T],
+                               md->pdata->frmwrk->abs[(CY_ABS_ID_OST *
+                               CY_NUM_ABS_SET) + CY_MAX_OST]);
+                       if (md->mt_function.input_sync)
+                               md->mt_function.input_sync(md->input);
+                       mt_sync_count++;
+                       continue;
+               }
+
+               /*
+                * if any touch is hover, then there is only one touch
+                * so it is OK to check the first touch for hover condition
+                */
+               if ((md->num_prv_tch == 0 && tch.abs[CY_TCH_O] != CY_OBJ_HOVER)
+                       || (md->prv_tch_type == CY_OBJ_HOVER
+                       && tch.abs[CY_TCH_O] != CY_OBJ_HOVER))
+                       input_report_key(md->input, BTN_TOUCH, CY_BTN_PRESSED);
+
+               /* use 0 based track id's */
+               sig = md->pdata->frmwrk->abs
+                       [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + 0];
+               if (sig != CY_IGNORE_VALUE) {
+                       t = tch.abs[CY_TCH_T] - md->pdata->frmwrk->abs
+                               [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST];
+                       if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF) {
+                               dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
+                                       __func__, t, tch.abs[CY_TCH_E]);
+                               goto cyttsp4_get_mt_touches_pr_tch;
+                       }
+                       if (md->mt_function.input_report)
+                               md->mt_function.input_report(md->input, sig, t);
+                       ids[t] = true;
+               }
+
+               /* Check if hover on this touch */
+               dev_vdbg(dev, "%s: t=%d z=%d\n", __func__, t,
+                       tch.abs[CY_TCH_P]);
+               if (t == CY_ACTIVE_STYLUS_ID) {
+                       tch.abs[CY_TCH_P] = 0;
+                       dev_dbg(dev, "%s: t=%d z=%d force zero\n", __func__, t,
+                               tch.abs[CY_TCH_P]);
+               }
+
+               /* all devices: position and pressure fields */
+               for (j = 0; j <= CY_ABS_W_OST ; j++) {
+                       sig = md->pdata->frmwrk->abs[((CY_ABS_X_OST + j) *
+                               CY_NUM_ABS_SET) + 0];
+                       if (sig != CY_IGNORE_VALUE)
+                               input_report_abs(md->input, sig,
+                                       tch.abs[CY_TCH_X + j]);
+               }
+               if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
+                       /*
+                        * TMA400 size and orientation fields:
+                        * if pressure is non-zero and major touch
+                        * signal is zero, then set major and minor touch
+                        * signals to minimum non-zero value
+                        */
+                       if (tch.abs[CY_TCH_P] > 0 && tch.abs[CY_TCH_MAJ] == 0)
+                               tch.abs[CY_TCH_MAJ] = tch.abs[CY_TCH_MIN] = 1;
+
+                       /* Get the extended touch fields */
+                       for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
+                               sig = md->pdata->frmwrk->abs
+                                       [((CY_ABS_MAJ_OST + j) *
+                                       CY_NUM_ABS_SET) + 0];
+                               if (sig != CY_IGNORE_VALUE)
+                                       input_report_abs(md->input, sig,
+                                               tch.abs[CY_TCH_MAJ + j]);
+                       }
+               }
+               if (md->mt_function.input_sync)
+                       md->mt_function.input_sync(md->input);
+               mt_sync_count++;
+
+cyttsp4_get_mt_touches_pr_tch:
+               if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE)
+                       dev_dbg(dev,
+                               "%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d\n",
+                               __func__, t,
+                               tch.abs[CY_TCH_X],
+                               tch.abs[CY_TCH_Y],
+                               tch.abs[CY_TCH_P],
+                               tch.abs[CY_TCH_MAJ],
+                               tch.abs[CY_TCH_MIN],
+                               tch.abs[CY_TCH_OR],
+                               tch.abs[CY_TCH_E]);
+               else
+                       dev_dbg(dev,
+                               "%s: t=%d x=%d y=%d z=%d e=%d\n", __func__,
+                               t,
+                               tch.abs[CY_TCH_X],
+                               tch.abs[CY_TCH_Y],
+                               tch.abs[CY_TCH_P],
+                               tch.abs[CY_TCH_E]);
+       }
+
+       if (md->mt_function.final_sync)
+               md->mt_function.final_sync(md->input, si->si_ofs.max_tchs,
+                               mt_sync_count, ids);
+
+       md->num_prv_tch = num_cur_tch;
+       md->prv_tch_type = tch.abs[CY_TCH_O];
+
+       return;
+}
+
+/* read xy_data for all current touches */
+static int cyttsp4_xy_worker(struct cyttsp4_mt_data *md)
+{
+       struct device *dev = &md->ttsp->dev;
+       struct cyttsp4_sysinfo *si = md->si;
+       u8 num_cur_tch;
+       u8 hst_mode;
+       u8 rep_len;
+       u8 rep_stat;
+       u8 tt_stat;
+       int rc = 0;
+
+       /*
+        * Get event data from cyttsp4 device.
+        * The event data includes all data
+        * for all active touches.
+        * Event data also includes button data
+        */
+       /*
+        * Use 2 reads:
+        * 1st read to get mode + button bytes + touch count (core)
+        * 2nd read (optional) to get touch 1 - touch n data
+        */
+       hst_mode = si->xy_mode[CY_REG_BASE];
+       rep_len = si->xy_mode[si->si_ofs.rep_ofs];
+       rep_stat = si->xy_mode[si->si_ofs.rep_ofs + 1];
+       tt_stat = si->xy_mode[si->si_ofs.tt_stat_ofs];
+       dev_vdbg(dev, "%s: %s%02X %s%d %s%02X %s%02X\n", __func__,
+               "hst_mode=", hst_mode, "rep_len=", rep_len,
+               "rep_stat=", rep_stat, "tt_stat=", tt_stat);
+
+       num_cur_tch = GET_NUM_TOUCHES(tt_stat);
+       dev_vdbg(dev, "%s: num_cur_tch=%d\n", __func__, num_cur_tch);
+
+       if (rep_len == 0 && num_cur_tch > 0) {
+               dev_err(dev, "%s: report length error rep_len=%d num_tch=%d\n",
+                       __func__, rep_len, num_cur_tch);
+               goto cyttsp4_xy_worker_exit;
+       }
+
+       /* read touches */
+       if (num_cur_tch > 0) {
+               rc = cyttsp4_read(md->ttsp, CY_MODE_OPERATIONAL,
+                       si->si_ofs.tt_stat_ofs + 1, si->xy_data,
+                       num_cur_tch * si->si_ofs.tch_rec_size);
+               if (rc < 0) {
+                       dev_err(dev, "%s: read fail on touch regs r=%d\n",
+                               __func__, rc);
+                       goto cyttsp4_xy_worker_exit;
+               }
+       }
+
+       /* print xy data */
+       cyttsp4_pr_buf(dev, md->pr_buf, si->xy_data, num_cur_tch *
+               si->si_ofs.tch_rec_size, "xy_data");
+
+       /* check any error conditions */
+       if (IS_BAD_PKT(rep_stat)) {
+               dev_dbg(dev, "%s: Invalid buffer detected\n", __func__);
+               rc = 0;
+               goto cyttsp4_xy_worker_exit;
+       } else if (IS_LARGE_AREA(tt_stat)) {
+               /* terminate all active tracks */
+               num_cur_tch = 0;
+               dev_dbg(dev, "%s: Large area detected\n", __func__);
+       } else if (num_cur_tch > si->si_ofs.max_tchs) {
+               if (num_cur_tch > max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)) {
+                       /* terminate all active tracks */
+                       dev_err(dev, "%s: Num touch err detected (n=%d)\n",
+                               __func__, num_cur_tch);
+                       num_cur_tch = 0;
+               } else {
+                       dev_err(dev, "%s: %s (n=%d c=%d)\n", __func__,
+                               "too many tch; set to max tch",
+                               num_cur_tch, si->si_ofs.max_tchs);
+                       num_cur_tch = si->si_ofs.max_tchs;
+               }
+       }
+
+       /* extract xy_data for all currently reported touches */
+       dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
+               num_cur_tch);
+       if (num_cur_tch)
+               cyttsp4_get_mt_touches(md, num_cur_tch);
+       else
+               cyttsp4_lift_all(md);
+
+       dev_vdbg(dev, "%s: done\n", __func__);
+       rc = 0;
+
+cyttsp4_xy_worker_exit:
+       return rc;
+}
+
+static int cyttsp4_mt_attention(struct cyttsp4_device *ttsp)
+{
+       struct device *dev = &ttsp->dev;
+       struct cyttsp4_mt_data *md = dev_get_drvdata(dev);
+       int rc = 0;
+
+       dev_vdbg(dev, "%s\n", __func__);
+
+       /* core handles handshake */
+       rc = cyttsp4_xy_worker(md);
+       if (rc < 0)
+               dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
+
+       return rc;
+}
+
+static int cyttsp4_startup_attention(struct cyttsp4_device *ttsp)
+{
+       struct device *dev = &ttsp->dev;
+       struct cyttsp4_mt_data *md = dev_get_drvdata(dev);
+       int rc = 0;
+
+       dev_vdbg(dev, "%s\n", __func__);
+
+       cyttsp4_lift_all(md);
+       return rc;
+}
+
+static int cyttsp4_mt_open(struct input_dev *input)
+{
+       struct device *dev = input->dev.parent;
+       struct cyttsp4_device *ttsp =
+               container_of(dev, struct cyttsp4_device, dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       pm_runtime_get_sync(dev);
+
+       dev_vdbg(dev, "%s: setup subscriptions\n", __func__);
+
+       /* set up touch call back */
+       cyttsp4_subscribe_attention(ttsp, CY_ATTEN_IRQ,
+               cyttsp4_mt_attention, CY_MODE_OPERATIONAL);
+
+       /* set up startup call back */
+       cyttsp4_subscribe_attention(ttsp, CY_ATTEN_STARTUP,
+               cyttsp4_startup_attention, 0);
+
+       return 0;
+}
+
+static void cyttsp4_mt_close(struct input_dev *input)
+{
+       struct device *dev = input->dev.parent;
+       struct cyttsp4_mt_data *md = dev_get_drvdata(dev);
+       struct cyttsp4_device *ttsp =
+               container_of(dev, struct cyttsp4_device, dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       cyttsp4_lift_all(md);
+
+       cyttsp4_unsubscribe_attention(ttsp, CY_ATTEN_IRQ,
+               cyttsp4_mt_attention, CY_MODE_OPERATIONAL);
+
+       cyttsp4_unsubscribe_attention(ttsp, CY_ATTEN_STARTUP,
+               cyttsp4_startup_attention, 0);
+
+       pm_runtime_put(dev);
+}
+
+
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+static int cyttsp4_mt_suspend(struct device *dev)
+{
+       struct cyttsp4_mt_data *md = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       cyttsp4_lift_all(md);
+       return 0;
+}
+
+static int cyttsp4_mt_resume(struct device *dev)
+{
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
+}
+#endif
+
+const struct dev_pm_ops cyttsp4_mt_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(cyttsp4_mt_suspend, cyttsp4_mt_resume)
+       SET_RUNTIME_PM_OPS(cyttsp4_mt_suspend, cyttsp4_mt_resume, NULL)
+};
+
+int cyttsp4_mt_release(struct cyttsp4_device *ttsp)
+{
+       struct device *dev = &ttsp->dev;
+       struct cyttsp4_mt_data *md = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+
+       input_unregister_device(md->input);
+
+       pm_runtime_suspend(dev);
+       pm_runtime_disable(dev);
+
+       dev_set_drvdata(dev, NULL);
+       kfree(md);
+       return 0;
+}
+
+static int cyttsp4_mt_probe(struct cyttsp4_device *ttsp)
+{
+       struct device *dev = &ttsp->dev;
+       struct cyttsp4_mt_data *md;
+       struct cyttsp4_mt_platform_data *pdata = dev_get_platdata(dev);
+       int signal = CY_IGNORE_VALUE;
+       int max_x, max_y, max_p, min, max;
+       int max_x_tmp, max_y_tmp;
+       int i;
+       int rc;
+
+       dev_info(dev, "%s\n", __func__);
+       dev_dbg(dev, "%s: debug on\n", __func__);
+       dev_vdbg(dev, "%s: verbose debug on\n", __func__);
+
+       md = kzalloc(sizeof(*md), GFP_KERNEL);
+       if (md == NULL) {
+               dev_err(dev, "%s: Error, kzalloc\n", __func__);
+               rc = -ENOMEM;
+               goto error_alloc_data_failed;
+       }
+
+       cyttsp4_init_function_ptrs(md);
+
+       md->prv_tch_type = CY_OBJ_STANDARD_FINGER;
+       md->ttsp = ttsp;
+       md->pdata = pdata;
+       dev_set_drvdata(dev, md);
+       /* Create the input device and register it. */
+       dev_vdbg(dev, "%s: Create the input device and register it\n",
+               __func__);
+       md->input = input_allocate_device();
+       if (md->input == NULL) {
+               dev_err(dev, "%s: Error, failed to allocate input device\n",
+                       __func__);
+               rc = -ENOSYS;
+               goto error_alloc_failed;
+       }
+
+       md->input->name = ttsp->name;
+       scnprintf(md->phys, sizeof(md->phys)-1, "%s", dev_name(dev));
+       md->input->phys = md->phys;
+       md->input->dev.parent = &md->ttsp->dev;
+       md->input->open = cyttsp4_mt_open;
+       md->input->close = cyttsp4_mt_close;
+       input_set_drvdata(md->input, md);
+
+       pm_runtime_enable(dev);
+
+       pm_runtime_get_sync(dev);
+       /* get sysinfo */
+       md->si = cyttsp4_request_sysinfo(ttsp);
+       pm_runtime_put(dev);
+
+       if (md->si == NULL) {
+               dev_err(dev, "%s: Fail get sysinfo pointer from core p=%p\n",
+                       __func__, md->si);
+               rc = -ENODEV;
+               goto error_get_sysinfo;
+       }
+
+       dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
+       __set_bit(EV_ABS, md->input->evbit);
+       __set_bit(EV_REL, md->input->evbit);
+       __set_bit(EV_KEY, md->input->evbit);
+       bitmap_fill(md->input->absbit, ABS_MAX);
+       __set_bit(BTN_TOUCH, md->input->keybit);
+
+       /* If virtualkeys enabled, don't use all screen */
+       if (md->pdata->flags & CY_FLAG_VKEYS) {
+               max_x_tmp = CY_VKEYS_X;
+               max_y_tmp = CY_VKEYS_Y;
+       } else {
+               max_x_tmp = md->si->si_ofs.max_x;
+               max_y_tmp = md->si->si_ofs.max_y;
+       }
+
+       /* get maximum values from the sysinfo data */
+       if (md->pdata->flags & CY_FLAG_FLIP) {
+               max_x = max_y_tmp - 1;
+               max_y = max_x_tmp - 1;
+       } else {
+               max_x = max_x_tmp - 1;
+               max_y = max_y_tmp - 1;
+       }
+       max_p = md->si->si_ofs.max_p;
+
+       /* set event signal capabilities */
+       for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) {
+               signal = md->pdata->frmwrk->abs
+                       [(i * CY_NUM_ABS_SET) + CY_SIGNAL_OST];
+               if (signal != CY_IGNORE_VALUE) {
+                       min = md->pdata->frmwrk->abs
+                               [(i * CY_NUM_ABS_SET) + CY_MIN_OST];
+                       max = md->pdata->frmwrk->abs
+                               [(i * CY_NUM_ABS_SET) + CY_MAX_OST];
+                       if (i == CY_ABS_ID_OST) {
+                               /* shift track ids down to start at 0 */
+                               max = max - min;
+                               min = min - min;
+                       } else if (i == CY_ABS_X_OST)
+                               max = max_x;
+                       else if (i == CY_ABS_Y_OST)
+                               max = max_y;
+                       else if (i == CY_ABS_P_OST)
+                               max = max_p;
+                       input_set_abs_params(md->input, signal, min, max,
+                               md->pdata->frmwrk->abs
+                               [(i * CY_NUM_ABS_SET) + CY_FUZZ_OST],
+                               md->pdata->frmwrk->abs
+                               [(i * CY_NUM_ABS_SET) + CY_FLAT_OST]);
+                       dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
+                               __func__, signal, min, max);
+                       if ((i == CY_ABS_ID_OST) &&
+                               (md->si->si_ofs.tch_rec_size <
+                               CY_TMA4XX_TCH_REC_SIZE))
+                               break;
+               }
+       }
+
+       rc = md->mt_function.input_register_device(md->input,
+                       md->si->si_ofs.max_tchs);
+       if (rc < 0) {
+               dev_err(dev, "%s: Error, failed register input device r=%d\n",
+                       __func__, rc);
+               goto error_init_input;
+       }
+
+       dev_dbg(dev, "%s: OK\n", __func__);
+       return 0;
+
+error_init_input:
+       input_free_device(md->input);
+error_get_sysinfo:
+       pm_runtime_suspend(dev);
+       pm_runtime_disable(dev);
+       input_set_drvdata(md->input, NULL);
+error_alloc_failed:
+       kfree(md);
+error_alloc_data_failed:
+       dev_err(dev, "%s failed.\n", __func__);
+       return rc;
+}
+
+struct cyttsp4_driver cyttsp4_mt_driver = {
+       .probe = cyttsp4_mt_probe,
+       .remove = cyttsp4_mt_release,
+       .driver = {
+               .name = CYTTSP4_MT_NAME,
+               .bus = &cyttsp4_bus_type,
+               .pm = &cyttsp4_mt_pm_ops,
+       },
+};
+
diff --git a/drivers/input/touchscreen/cyttsp4_mt_common.h b/drivers/input/touchscreen/cyttsp4_mt_common.h
new file mode 100644
index 0000000..d363e9e0
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_mt_common.h
@@ -0,0 +1,76 @@
+/*
+ * cyttsp4_mt_common.h
+ * Cypress TrueTouch(TM) Standard Product V4 Multi-touch module.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * 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 <ttdrivers@cypress.com>
+ *
+ */
+
+#include <linux/cyttsp4_bus.h>
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include <linux/cyttsp4_core.h>
+#include <linux/cyttsp4_mt.h>
+#include "cyttsp4_regs.h"
+
+struct cyttsp4_mt_data;
+struct cyttsp4_mt_function {
+       int (*mt_release)(struct cyttsp4_device *ttsp);
+       int (*mt_probe)(struct cyttsp4_device *ttsp,
+                       struct cyttsp4_mt_data *md);
+       void (*report_slot_liftoff)(struct cyttsp4_mt_data *md);
+       void (*input_sync)(struct input_dev *input);
+       void (*input_report)(struct input_dev *input, int sig, int t);
+       void (*final_sync)(struct input_dev *input, int max_tchs,
+                       int mt_sync_count, int *ids);
+       int (*input_register_device)(struct input_dev *input, int max_tchs);
+};
+
+struct cyttsp4_mt_data {
+       struct cyttsp4_device *ttsp;
+       struct cyttsp4_mt_platform_data *pdata;
+       struct cyttsp4_sysinfo *si;
+       struct input_dev *input;
+       struct cyttsp4_mt_function mt_function;
+       char phys[NAME_MAX];
+       int num_prv_tch;
+       int prv_tch_type;
+#ifdef VERBOSE_DEBUG
+       u8 pr_buf[CY_MAX_PRBUF_SIZE];
+#endif
+};
+
+extern void cyttsp4_init_function_ptrs(struct cyttsp4_mt_data *md);
+extern struct cyttsp4_driver cyttsp4_mt_driver;
+
diff --git a/drivers/input/touchscreen/cyttsp4_mtb.c b/drivers/input/touchscreen/cyttsp4_mtb.c
new file mode 100644
index 0000000..7a0b7b1
--- /dev/null
+++ b/drivers/input/touchscreen/cyttsp4_mtb.c
@@ -0,0 +1,107 @@
+/*
+ * cyttsp4_mtb.c
+ * Cypress TrueTouch(TM) Standard Product V4 Multi-touch module.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * 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 <ttdrivers@cypress.com>
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/input/mt.h>
+
+#include "cyttsp4_mt_common.h"
+
+static void cyttsp4_final_sync(struct input_dev *input, int max_tchs,
+               int mt_sync_count, int *ids)
+{
+       int t;
+
+       for (t = 0; t < max_tchs + 1; t++) {
+               if (ids[t])
+                       continue;
+               input_mt_slot(input, t);
+               input_mt_report_slot_state(input, MT_TOOL_FINGER, false);
+       }
+
+       input_sync(input);
+}
+
+static void cyttsp4_input_report(struct input_dev *input, int sig, int t)
+{
+       input_mt_slot(input, t);
+       input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+}
+
+static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md)
+{
+       struct cyttsp4_sysinfo *si = md->si;
+       int t;
+
+       if (md->num_prv_tch == 0)
+               return;
+
+       for (t = 0; t < si->si_ofs.max_tchs + 1; t++) {
+               input_mt_slot(md->input, t);
+               input_mt_report_slot_state(md->input,
+                       MT_TOOL_FINGER, false);
+       }
+}
+
+static int cyttsp4_input_register_device(struct input_dev *input, int max_tchs)
+{
+       /* max num slots equals max touches + 1 for hover */
+       input_mt_init_slots(input, max_tchs + 1);
+       return input_register_device(input);
+}
+
+void cyttsp4_init_function_ptrs(struct cyttsp4_mt_data *md)
+{
+       md->mt_function.report_slot_liftoff = cyttsp4_report_slot_liftoff;
+       md->mt_function.final_sync = cyttsp4_final_sync;
+       md->mt_function.input_sync = NULL;
+       md->mt_function.input_report = cyttsp4_input_report;
+       md->mt_function.input_register_device = cyttsp4_input_register_device;
+}
+
+static int __init cyttsp4_mt_init(void)
+{
+       int rc;
+       cyttsp4_mt_driver.driver.owner = THIS_MODULE;
+       rc = cyttsp4_register_driver(&cyttsp4_mt_driver);
+       pr_info("%s: Cypress TTSP MT v4 multi-touch (Built %s @ %s), rc=%d\n",
+                __func__, __DATE__, __TIME__, rc);
+       return rc;
+}
+module_init(cyttsp4_mt_init);
+
+static void __exit cyttsp4_mt_exit(void)
+{
+       cyttsp4_unregister_driver(&cyttsp4_mt_driver);
+       pr_info("%s: module exit\n", __func__);
+}
+module_exit(cyttsp4_mt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard 2D multi-touch driver");
+MODULE_AUTHOR("Cypress Semiconductor");
diff --git a/include/linux/cyttsp4_mt.h b/include/linux/cyttsp4_mt.h
new file mode 100644
index 0000000..4339544
--- /dev/null
+++ b/include/linux/cyttsp4_mt.h
@@ -0,0 +1,72 @@
+/*
+ * cyttsp4_mt.h
+ * Cypress TrueTouch(TM) Standard Product V4 Multi-touch module.
+ * For use with Cypress Txx4xx parts.
+ * Supported parts include:
+ * TMA4XX
+ * TMA1036
+ *
+ * Copyright (C) 2012 Cypress Semiconductor
+ * Copyright (C) 2011 Sony Ericsson Mobile Communications AB.
+ *
+ * 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 <ttdrivers@cypress.com>
+ *
+ */
+
+#ifndef _LINUX_CYTTSP4_MT_H
+#define _LINUX_CYTTSP4_MT_H
+
+#define CYTTSP4_MT_NAME "cyttsp4_mt"
+
+/* abs settings */
+#define CY_IGNORE_VALUE             0xFFFF
+/* abs signal capabilities offsets in the frameworks array */
+enum cyttsp4_sig_caps {
+       CY_SIGNAL_OST,
+       CY_MIN_OST,
+       CY_MAX_OST,
+       CY_FUZZ_OST,
+       CY_FLAT_OST,
+       CY_NUM_ABS_SET  /* number of signal capability fields */
+};
+
+/* abs axis signal offsets in the framworks array  */
+enum cyttsp4_sig_ost {
+       CY_ABS_X_OST,
+       CY_ABS_Y_OST,
+       CY_ABS_P_OST,
+       CY_ABS_W_OST,
+       CY_ABS_ID_OST,
+       CY_ABS_MAJ_OST,
+       CY_ABS_MIN_OST,
+       CY_ABS_OR_OST,
+       CY_NUM_ABS_OST  /* number of abs signals */
+};
+
+struct touch_framework {
+       const uint16_t  *abs;
+       uint8_t         size;
+       uint8_t         enable_vkeys;
+} __packed;
+
+struct cyttsp4_mt_platform_data {
+       struct touch_framework *frmwrk;
+       unsigned short flags;
+       char const *inp_dev_name;
+};
+
+#endif /* _LINUX_CYTTSP4_MT_H */
--
1.7.9.5


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.

  parent reply	other threads:[~2012-08-07 13:15 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <Ferruh Yigit <fery@cypress.com>
2012-08-07 13:09 ` [PATCH 1/4] Input: cyttsp4 - bus driver for Cypress TMA4XX touchscreen devices Ferruh Yigit
2012-08-07 20:05   ` Javier Martinez Canillas
2012-08-08  5:53     ` Ferruh Yigit
2012-08-24 13:06   ` Ferruh Yigit
2012-08-24 17:34     ` Henrik Rydberg
     [not found]       ` <503B099A.6010807@cypress.com>
2012-09-12 13:16         ` Ferruh Yigit
2012-09-12 13:34           ` Henrik Rydberg
2012-08-07 13:09 ` [PATCH 2/4] Input: cyttsp4 - core " Ferruh Yigit
2012-08-24 14:21   ` Michal Marek
2012-08-27  5:49     ` Ferruh Yigit
2012-08-07 13:10 ` Ferruh Yigit [this message]
2012-08-07 13:10 ` [PATCH 4/4] Input: cyttsp4 - I2C " Ferruh Yigit
2012-09-14 17:48 ` [PATCH v2 0/3] Input: cyttsp4 - " Ferruh Yigit
2012-09-14 17:48   ` [PATCH v2 1/3] Input: cyttsp4 - core " Ferruh Yigit
2012-09-14 17:48   ` [PATCH v2 2/3] Input: cyttsp4 - I2C " Ferruh Yigit
2012-09-14 17:48   ` [PATCH v2 3/3] Input: cyttsp4 - SPI " Ferruh Yigit
2012-09-14 18:46   ` [PATCH v2 0/3] Input: cyttsp4 - " Henrik Rydberg
2012-09-15 15:42     ` Javier Martinez Canillas
2012-09-19 12:02       ` Ferruh Yigit
2012-09-19 11:53     ` Ferruh Yigit

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1344345032-30537-1-git-send-email-fery@cypress.com \
    --to=fery@cypress.com \
    --cc=ashish.jangam@kpitcummins.com \
    --cc=dmitry.torokhov@gmail.com \
    --cc=javier@dowhile0.org \
    --cc=kev@cypress.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=olivier@sobrie.be \
    --cc=rydberg@euromail.se \
    --cc=shawnlandden@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).