From patchwork Wed Dec 18 09:21:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roger Quadros X-Patchwork-Id: 3368991 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 8AB3EC0D4A for ; Wed, 18 Dec 2013 09:25:02 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0F44520453 for ; Wed, 18 Dec 2013 09:25:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A41532044C for ; Wed, 18 Dec 2013 09:24:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753095Ab3LRJYm (ORCPT ); Wed, 18 Dec 2013 04:24:42 -0500 Received: from comal.ext.ti.com ([198.47.26.152]:51637 "EHLO comal.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753653Ab3LRJWm (ORCPT ); Wed, 18 Dec 2013 04:22:42 -0500 Received: from dflxv15.itg.ti.com ([128.247.5.124]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id rBI9McAY006482; Wed, 18 Dec 2013 03:22:38 -0600 Received: from DLEE71.ent.ti.com (dlee71.ent.ti.com [157.170.170.114]) by dflxv15.itg.ti.com (8.14.3/8.13.8) with ESMTP id rBI9Mckt025309; Wed, 18 Dec 2013 03:22:38 -0600 Received: from dflp32.itg.ti.com (10.64.6.15) by DLEE71.ent.ti.com (157.170.170.114) with Microsoft SMTP Server id 14.2.342.3; Wed, 18 Dec 2013 03:22:37 -0600 Received: from localhost.localdomain (ileax41-snat.itg.ti.com [10.172.224.153]) by dflp32.itg.ti.com (8.14.3/8.13.8) with ESMTP id rBI9LjTx008288; Wed, 18 Dec 2013 03:22:32 -0600 From: Roger Quadros To: CC: , , , , , Roger Quadros Subject: [PATCH 7/9] Input: pixcir_i2c_ts: Implement Type B Multi Touch reporting Date: Wed, 18 Dec 2013 14:51:18 +0530 Message-ID: <1387358480-8313-8-git-send-email-rogerq@ti.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com> References: <1387358480-8313-1-git-send-email-rogerq@ti.com> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Some pixcir controllers e.g. tangoC family report finger IDs with the co-ordinates and are more suitable for Type-B MT protocol. Signed-off-by: Roger Quadros Acked-by: Mugunthan V N --- drivers/input/touchscreen/pixcir_i2c_ts.c | 202 +++++++++++++++++++++++------- 1 file changed, 155 insertions(+), 47 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index ff68246..9e14415 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -23,84 +23,173 @@ #include #include #include +#include #include #include #include #include #include +#define MAX_FINGERS 5 /* Maximum supported by the driver */ + struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; const struct pixcir_ts_platform_data *pdata; bool exiting; + u8 max_fingers; /* Maximum supported by the chip */ }; -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) +static void pixcir_ts_typea_report(struct pixcir_i2c_ts_data *tsdata) { - struct pixcir_i2c_ts_data *tsdata = data; + const struct pixcir_ts_platform_data *pdata = tsdata->pdata; u8 rdbuf[10], wrbuf[1] = { 0 }; u8 touch; int ret; - ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf)); - if (ret != sizeof(wrbuf)) { - dev_err(&tsdata->client->dev, - "%s: i2c_master_send failed(), ret=%d\n", - __func__, ret); - return; - } + while (!tsdata->exiting) { - ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf)); - if (ret != sizeof(rdbuf)) { - dev_err(&tsdata->client->dev, - "%s: i2c_master_recv failed(), ret=%d\n", - __func__, ret); - return; - } + ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf)); + if (ret != sizeof(wrbuf)) { + dev_err(&tsdata->client->dev, + "%s: i2c_master_send failed(), ret=%d\n", + __func__, ret); + return; + } + + ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf)); + if (ret != sizeof(rdbuf)) { + dev_err(&tsdata->client->dev, + "%s: i2c_master_recv failed(), ret=%d\n", + __func__, ret); + return; + } - touch = rdbuf[0]; - if (touch) { - u16 posx1 = (rdbuf[3] << 8) | rdbuf[2]; - u16 posy1 = (rdbuf[5] << 8) | rdbuf[4]; - u16 posx2 = (rdbuf[7] << 8) | rdbuf[6]; - u16 posy2 = (rdbuf[9] << 8) | rdbuf[8]; - - input_report_key(tsdata->input, BTN_TOUCH, 1); - input_report_abs(tsdata->input, ABS_X, posx1); - input_report_abs(tsdata->input, ABS_Y, posy1); - - input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1); - input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1); - input_mt_sync(tsdata->input); - - if (touch == 2) { - input_report_abs(tsdata->input, - ABS_MT_POSITION_X, posx2); - input_report_abs(tsdata->input, - ABS_MT_POSITION_Y, posy2); + touch = rdbuf[0]; + if (touch) { + u16 posx1 = (rdbuf[3] << 8) | rdbuf[2]; + u16 posy1 = (rdbuf[5] << 8) | rdbuf[4]; + u16 posx2 = (rdbuf[7] << 8) | rdbuf[6]; + u16 posy2 = (rdbuf[9] << 8) | rdbuf[8]; + + input_report_key(tsdata->input, BTN_TOUCH, 1); + input_report_abs(tsdata->input, ABS_X, posx1); + input_report_abs(tsdata->input, ABS_Y, posy1); + + input_report_abs(tsdata->input, ABS_MT_POSITION_X, + posx1); + input_report_abs(tsdata->input, ABS_MT_POSITION_Y, + posy1); input_mt_sync(tsdata->input); + + if (touch == 2) { + input_report_abs(tsdata->input, + ABS_MT_POSITION_X, posx2); + input_report_abs(tsdata->input, + ABS_MT_POSITION_Y, posy2); + input_mt_sync(tsdata->input); + } + } else { + input_report_key(tsdata->input, BTN_TOUCH, 0); } - } else { - input_report_key(tsdata->input, BTN_TOUCH, 0); - } - input_sync(tsdata->input); + input_sync(tsdata->input); + + if (gpio_get_value(pdata->gpio_attb)) + break; + + msleep(20); + } } -static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) +static void pixcir_ts_typeb_report(struct pixcir_i2c_ts_data *ts) { - struct pixcir_i2c_ts_data *tsdata = dev_id; - const struct pixcir_ts_platform_data *pdata = tsdata->pdata; + const struct pixcir_ts_platform_data *pdata = ts->pdata; + struct device *dev = &ts->client->dev; + u8 rdbuf[32], wrbuf[1] = { 0 }; + u8 *bufptr; + u8 num_fingers; + u8 unreliable; + int ret, i; + + while (!ts->exiting) { + + ret = i2c_master_send(ts->client, wrbuf, sizeof(wrbuf)); + if (ret != sizeof(wrbuf)) { + dev_err(dev, "%s: i2c_master_send failed(), ret=%d\n", + __func__, ret); + return; + } - while (!tsdata->exiting) { - pixcir_ts_poscheck(tsdata); + ret = i2c_master_recv(ts->client, rdbuf, sizeof(rdbuf)); + if (ret != sizeof(rdbuf)) { + dev_err(dev, "%s: i2c_master_recv failed(), ret=%d\n", + __func__, ret); + return; + } + + unreliable = rdbuf[0] & 0xe0; + + if (unreliable) + goto next; /* ignore unreliable data */ + + num_fingers = rdbuf[0] & 0x7; + bufptr = &rdbuf[2]; + if (num_fingers > ts->max_fingers) { + num_fingers = ts->max_fingers; + dev_dbg(dev, "limiting num_fingers to %d\n", + num_fingers); + } + + for (i = 0; i < num_fingers; i++) { + u8 id; + unsigned int x, y; + int slot; + + id = bufptr[4]; + slot = input_mt_get_slot_by_key(ts->input, id); + if (slot < 0) { + dev_dbg(dev, "no free slot for id 0x%x\n", id); + continue; + } + + + x = bufptr[1] << 8 | bufptr[0]; + y = bufptr[3] << 8 | bufptr[2]; + + input_mt_slot(ts->input, slot); + input_mt_report_slot_state(ts->input, + MT_TOOL_FINGER, true); + + input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, x); + input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, y); + + bufptr = &bufptr[5]; + dev_dbg(dev, "%d: id 0x%x slot %d, x %d, y %d\n", + i, id, slot, x, y); + } + + /* One frame is complete so sync it */ + input_mt_sync_frame(ts->input); + input_sync(ts->input); + +next: if (gpio_get_value(pdata->gpio_attb)) break; - msleep(20); + usleep_range(2000, 5000); } +} + +static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) +{ + struct pixcir_i2c_ts_data *tsdata = dev_id; + + if (tsdata->input->mt) + pixcir_ts_typeb_report(tsdata); + else + pixcir_ts_typea_report(tsdata); return IRQ_HANDLED; } @@ -376,9 +465,9 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->open = pixcir_input_open; input->close = pixcir_input_close; - __set_bit(EV_KEY, input->evbit); __set_bit(EV_ABS, input->evbit); __set_bit(BTN_TOUCH, input->keybit); + input_set_abs_params(input, ABS_X, 0, pdata->x_size - 1, 0, 0); input_set_abs_params(input, ABS_Y, @@ -388,6 +477,25 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_size - 1, 0, 0); + /* Type-B Multi-Touch support */ + if (pdata->chip.num_report_ids) { + const struct pixcir_i2c_chip_data *chip = &pdata->chip; + + tsdata->max_fingers = chip->num_report_ids; + if (tsdata->max_fingers > MAX_FINGERS) { + dev_info(dev, "Limiting maximum fingers to %d\n", + MAX_FINGERS); + tsdata->max_fingers = MAX_FINGERS; + } + + error = input_mt_init_slots(input, tsdata->max_fingers, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(dev, "Error initializing Multi-Touch slots\n"); + return error; + } + } + input_set_drvdata(input, tsdata); error = devm_gpio_request_one(dev, pdata->gpio_attb,