From patchwork Thu Jan 3 01:29:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Vasut X-Patchwork-Id: 10746903 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F3A5D14DE for ; Thu, 3 Jan 2019 01:30:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E40AB28415 for ; Thu, 3 Jan 2019 01:30:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D85AB2841E; Thu, 3 Jan 2019 01:30:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3882D28415 for ; Thu, 3 Jan 2019 01:30:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727247AbfACBaY (ORCPT ); Wed, 2 Jan 2019 20:30:24 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:46191 "EHLO mail-out.m-online.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727211AbfACBaY (ORCPT ); Wed, 2 Jan 2019 20:30:24 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 43VVjB57mwz1qvgR; Thu, 3 Jan 2019 02:30:22 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 43VVjB4xc4z1qvWb; Thu, 3 Jan 2019 02:30:22 +0100 (CET) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id ndY9U9x-RLZ2; Thu, 3 Jan 2019 02:30:21 +0100 (CET) X-Auth-Info: kAC2dVFPBb7AZDZsOZ8tiwf0seWpqZNhIu29uepcTJY= Received: from kurokawa.lan (ip-86-49-110-70.net.upcbroadband.cz [86.49.110.70]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Thu, 3 Jan 2019 02:30:21 +0100 (CET) From: Marek Vasut To: linux-input@vger.kernel.org Cc: Marek Vasut , Dmitry Torokhov , Henrik Rydberg , Olivier Sobrie , Philipp Puschmann Subject: [PATCH V3 10/10] input: touchscreen: ili210x: Add ILI251X support Date: Thu, 3 Jan 2019 02:29:38 +0100 Message-Id: <20190103012938.7442-11-marex@denx.de> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20190103012938.7442-1-marex@denx.de> References: <20190103012938.7442-1-marex@denx.de> MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add support for ILI251x touch controller. This controller is similar to the ILI210x, except for the following differences: - Does not support I2C R-W transfer, Read must be followed by an obscenely long delay, and then followed by Write - Does support 10 simultaneous touch inputs. - Touch data format is slightly different, pressure reporting does not work although the touch data contain such information. Signed-off-by: Marek Vasut Cc: Dmitry Torokhov Cc: Henrik Rydberg Cc: Olivier Sobrie Cc: Philipp Puschmann To: linux-input@vger.kernel.org --- V2: - Implement delayed work for ILI251x - Fix operation with >6 fingers in ili210x_work V3: - Use get_unaligned_be16() --- drivers/input/touchscreen/ili210x.c | 119 ++++++++++++++++++++++++---- 1 file changed, 104 insertions(+), 15 deletions(-) diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index bc327d75c046..7da46c293a74 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -6,9 +6,11 @@ #include #include #include +#include #include -#define MAX_TOUCHES 2 +#define ILI210X_TOUCHES 2 +#define ILI251X_TOUCHES 10 #define DEFAULT_POLL_PERIOD 20 /* Touchscreen commands */ @@ -32,17 +34,25 @@ struct firmware_version { u8 minor; } __packed; +enum ili2xxx_model { + MODEL_ILI210X, + MODEL_ILI251X, +}; + struct ili210x { struct i2c_client *client; struct input_dev *input; unsigned int poll_period; struct delayed_work dwork; struct gpio_desc *reset_gpio; + enum ili2xxx_model model; + unsigned int max_touches; }; static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, size_t len) { + struct ili210x *priv = i2c_get_clientdata(client); struct i2c_msg msg[2] = { { .addr = client->addr, @@ -58,7 +68,38 @@ static int ili210x_read_reg(struct i2c_client *client, u8 reg, void *buf, } }; - if (i2c_transfer(client->adapter, msg, 2) != 2) { + if (priv->model == MODEL_ILI251X) { + if (i2c_transfer(client->adapter, msg, 1) != 1) { + dev_err(&client->dev, "i2c transfer failed\n"); + return -EIO; + } + + mdelay(5); + + if (i2c_transfer(client->adapter, msg + 1, 1) != 1) { + dev_err(&client->dev, "i2c transfer failed\n"); + return -EIO; + } + } else { + if (i2c_transfer(client->adapter, msg, 2) != 2) { + dev_err(&client->dev, "i2c transfer failed\n"); + return -EIO; + } + } + + return 0; +} + +static int ili210x_read(struct i2c_client *client, void *buf, size_t len) +{ + struct i2c_msg msg = { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = buf, + }; + + if (i2c_transfer(client->adapter, &msg, 1) != 1) { dev_err(&client->dev, "i2c transfer failed\n"); return -EIO; } @@ -70,7 +111,7 @@ static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, unsigned int finger, unsigned int *x, unsigned int *y) { - if (finger >= MAX_TOUCHES) + if (finger >= ILI210X_TOUCHES) return false; if (touchdata[0] & BIT(finger)) @@ -82,16 +123,43 @@ static bool ili210x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, return true; } +static bool ili251x_touchdata_to_coords(struct ili210x *priv, u8 *touchdata, + unsigned int finger, + unsigned int *x, unsigned int *y) +{ + if (finger >= ILI251X_TOUCHES) + return false; + + *x = get_unaligned_be16(touchdata + 1 + (finger * 5) + 0); + if (!(*x & BIT(15))) /* Touch indication */ + return false; + + *x &= 0x3fff; + *y = get_unaligned_be16(touchdata + 1 + (finger * 5) + 2); + + return true; +} + static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) { + struct input_dev *input = priv->input; int i; - bool touch; - unsigned int x, y; + bool contact = false, touch = false; + unsigned int x = 0, y = 0; - for (i = 0; i < MAX_TOUCHES; i++) { + for (i = 0; i < priv->max_touches; i++) { input_mt_slot(input, i); - touch = ili210x_touchdata_to_coords(priv, touchdata, i, &x, &y); + if (priv->model == MODEL_ILI210X) { + touch = ili210x_touchdata_to_coords(priv, touchdata, + i, &x, &y); + } else if (priv->model == MODEL_ILI251X) { + touch = ili251x_touchdata_to_coords(priv, touchdata, + i, &x, &y); + if (touch) + contact = true; + } + input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); if (touch) { input_report_abs(input, ABS_MT_POSITION_X, x); @@ -102,7 +170,10 @@ static bool ili210x_report_events(struct ili210x *priv, u8 *touchdata) input_mt_report_pointer_emulation(input, false); input_sync(input); - return touchdata[0] & 0xf3; + if (priv->model == MODEL_ILI210X) + contact = touchdata[0] & 0xf3; + + return contact; } static void ili210x_work(struct work_struct *work) @@ -110,12 +181,20 @@ static void ili210x_work(struct work_struct *work) struct ili210x *priv = container_of(work, struct ili210x, dwork.work); struct i2c_client *client = priv->client; - u8 touchdata[1 + 4 * MAX_TOUCHES]; + u8 touchdata[64] = { 0 }; bool touch; - int error; + int error = -EINVAL; + + if (priv->model == MODEL_ILI210X) { + error = ili210x_read_reg(client, REG_TOUCHDATA, + touchdata, sizeof(touchdata)); + } else if (priv->model == MODEL_ILI251X) { + error = ili210x_read_reg(client, REG_TOUCHDATA, + touchdata, 31); + if (!error && touchdata[0] == 2) + error = ili210x_read(client, &touchdata[31], 20); + } - error = ili210x_read_reg(client, REG_TOUCHDATA, - touchdata, sizeof(touchdata)); if (error) { dev_err(&client->dev, "Unable to get touchdata, err = %d\n", error); @@ -189,9 +268,12 @@ static int ili210x_i2c_probe(struct i2c_client *client, struct input_dev *input; struct panel_info panel; struct firmware_version firmware; + enum ili2xxx_model model; int xmax, ymax; int error; + model = (enum ili2xxx_model)id->driver_data; + dev_dbg(dev, "Probing for ILI210X I2C Touschreen driver"); if (client->irq <= 0) { @@ -228,6 +310,11 @@ static int ili210x_i2c_probe(struct i2c_client *client, priv->poll_period = DEFAULT_POLL_PERIOD; INIT_DELAYED_WORK(&priv->dwork, ili210x_work); priv->reset_gpio = reset_gpio; + priv->model = model; + if (model == MODEL_ILI210X) + priv->max_touches = ILI210X_TOUCHES; + if (model == MODEL_ILI251X) + priv->max_touches = ILI251X_TOUCHES; i2c_set_clientdata(client, priv); @@ -266,7 +353,7 @@ static int ili210x_i2c_probe(struct i2c_client *client, input_set_abs_params(input, ABS_Y, 0, ymax, 0, 0); /* Multi touch */ - input_mt_init_slots(input, MAX_TOUCHES, 0); + input_mt_init_slots(input, priv->max_touches, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, xmax, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ymax, 0, 0); @@ -338,13 +425,15 @@ static SIMPLE_DEV_PM_OPS(ili210x_i2c_pm, ili210x_i2c_suspend, ili210x_i2c_resume); static const struct i2c_device_id ili210x_i2c_id[] = { - { "ili210x", 0 }, + { "ili210x", MODEL_ILI210X }, + { "ili251x", MODEL_ILI251X }, { } }; MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); static const struct of_device_id ili210x_dt_ids[] = { - { .compatible = "ilitek,ili210x", }, + { .compatible = "ilitek,ili210x", .data = (void *)MODEL_ILI210X }, + { .compatible = "ilitek,ili251x", .data = (void *)MODEL_ILI251X }, { }, }; MODULE_DEVICE_TABLE(of, ili210x_dt_ids);