From patchwork Mon Jun 29 16:28:20 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: tip-bot for Irina Tirdea X-Patchwork-Id: 6690071 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.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 14F61C05AC for ; Mon, 29 Jun 2015 16:30:46 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 147F320546 for ; Mon, 29 Jun 2015 16:30:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AC2A0205E4 for ; Mon, 29 Jun 2015 16:30:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753397AbbF2Qah (ORCPT ); Mon, 29 Jun 2015 12:30:37 -0400 Received: from mga09.intel.com ([134.134.136.24]:52189 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752674AbbF2Q3c (ORCPT ); Mon, 29 Jun 2015 12:29:32 -0400 Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP; 29 Jun 2015 09:29:33 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.13,699,1427785200"; d="scan'208";a="516031189" Received: from itirdea-desk.rb.intel.com ([10.237.104.94]) by FMSMGA003.fm.intel.com with ESMTP; 29 Jun 2015 09:29:29 -0700 From: Irina Tirdea To: Dmitry Torokhov , Bastien Nocera , Mark Rutland , linux-input@vger.kernel.org, devicetree@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Rob Herring , Pawel Moll , Ian Campbell , Kumar Gala , Irina Tirdea , Octavian Purdila Subject: [PATCH v3 1/5] Input: goodix - reset device at init Date: Mon, 29 Jun 2015 19:28:20 +0300 Message-Id: <1435595304-4840-2-git-send-email-irina.tirdea@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1435595304-4840-1-git-send-email-irina.tirdea@intel.com> References: <1435595304-4840-1-git-send-email-irina.tirdea@intel.com> 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.5 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 After power on, it is recommended that the driver resets the device. The reset procedure timing is described in the datasheet and is used at device init (before writing device configuration) and for power management. It is a sequence of setting the interrupt and reset pins high/low at specific timing intervals. This procedure also includes setting the slave address to the one specified in the ACPI/device tree. This is based on Goodix datasheets for GT911 and GT9271 and on Goodix driver gt9xx.c for Android (publicly available in Android kernel trees for various devices). For reset the driver needs to control the interrupt and reset gpio pins (configured through ACPI/device tree). For devices that do not have the gpio pins declared, the functionality depending on these pins will not be available, but the device can still be used with basic functionality. Signed-off-by: Octavian Purdila Signed-off-by: Irina Tirdea --- .../bindings/input/touchscreen/goodix.txt | 5 + drivers/input/touchscreen/goodix.c | 131 ++++++++++++++++++++- 2 files changed, 134 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt index 8ba98ee..c0715f8 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/goodix.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/goodix.txt @@ -12,6 +12,8 @@ Required properties: - reg : I2C address of the chip. Should be 0x5d or 0x14 - interrupt-parent : Interrupt controller to which the chip is connected - interrupts : Interrupt to which the chip is connected + - gpios : GPIOS the chip is connected to: first one is the + interrupt gpio and second one the reset gpio. Example: @@ -23,6 +25,9 @@ Example: reg = <0x5d>; interrupt-parent = <&gpio>; interrupts = <0 0>; + + gpios = <&gpio1 0 0>, /* INT */ + <&gpio1 1 0>; /* RST */ }; /* ... */ diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b4d12e2..80100f9 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,13 @@ struct goodix_ts_data { int abs_y_max; unsigned int max_touch_num; unsigned int int_trigger_type; + struct gpio_desc *gpiod_int; + struct gpio_desc *gpiod_rst; +}; + +struct goodix_gpio_data { + u8 irq_idx; + u8 rst_idx; }; #define GOODIX_MAX_HEIGHT 4096 @@ -60,6 +68,16 @@ static const unsigned long goodix_irq_flags[] = { IRQ_TYPE_LEVEL_HIGH, }; +static const struct goodix_gpio_data goodix_gpio_irq_rst = { + .irq_idx = 0, + .rst_idx = 1, +}; + +static const struct goodix_gpio_data goodix_gpio_rst_irq = { + .irq_idx = 1, + .rst_idx = 0, +}; + /** * goodix_i2c_read - read data from a register of the i2c slave device. * @@ -186,6 +204,102 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int goodix_int_sync(struct goodix_ts_data *ts) +{ + int ret; + + ret = gpiod_direction_output(ts->gpiod_int, 0); + if (ret) + return ret; + msleep(50); /* T5: 50ms */ + + return gpiod_direction_input(ts->gpiod_int); +} + +/** + * goodix_reset - Reset device during power on + * + * @ts: goodix_ts_data pointer + */ +static int goodix_reset(struct goodix_ts_data *ts) +{ + int ret; + + /* begin select I2C slave addr */ + ret = gpiod_direction_output(ts->gpiod_rst, 0); + if (ret) + return ret; + msleep(20); /* T2: > 10ms */ + /* HIGH: 0x28/0x29, LOW: 0xBA/0xBB */ + ret = gpiod_direction_output(ts->gpiod_int, ts->client->addr == 0x14); + if (ret) + return ret; + usleep_range(100, 2000); /* T3: > 100us */ + ret = gpiod_direction_output(ts->gpiod_rst, 1); + if (ret) + return ret; + usleep_range(6000, 10000); /* T4: > 5ms */ + /* end select I2C slave addr */ + ret = gpiod_direction_input(ts->gpiod_rst); + if (ret) + return ret; + return goodix_int_sync(ts); +} + +/** + * goodix_get_gpio_config - Get GPIO config from ACPI/DT + * + * @ts: goodix_ts_data pointer + */ +static int goodix_get_gpio_config(struct goodix_ts_data *ts, + const struct i2c_device_id *i2c_id) +{ + int ret; + struct device *dev; + const struct acpi_device_id *acpi_id; + struct gpio_desc *gpiod; + /* Default gpio pin order: irq, rst */ + const struct goodix_gpio_data *gpio = &goodix_gpio_irq_rst; + + if (!ts->client) + return -EINVAL; + dev = &ts->client->dev; + + /* Set gpio pin order if specified in chip data */ + if (i2c_id) { + if (i2c_id->driver_data) + gpio = (struct goodix_gpio_data *)i2c_id->driver_data; + } else if (ACPI_HANDLE(dev)) { + acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (acpi_id) + gpio = (struct goodix_gpio_data *)acpi_id->driver_data; + } + + /* Get interrupt GPIO pin number */ + gpiod = devm_gpiod_get_index(dev, NULL, gpio->irq_idx, GPIOD_IN); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + if (ret != -EPROBE_DEFER) + dev_warn(dev, "Failed to get GPIO %d: %d\n", + gpio->irq_idx, ret); + return ret; + } + ts->gpiod_int = gpiod; + + /* Get the reset line GPIO pin number */ + gpiod = devm_gpiod_get_index(dev, NULL, gpio->rst_idx, GPIOD_IN); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + if (ret != -EPROBE_DEFER) + dev_warn(dev, "Failed to get GPIO %d: %d\n", + gpio->rst_idx, ret); + return ret; + } + ts->gpiod_rst = gpiod; + + return 0; +} + /** * goodix_read_config - Read the embedded configuration of the panel * @@ -362,6 +476,19 @@ static int goodix_ts_probe(struct i2c_client *client, return error; } + error = goodix_get_gpio_config(ts, id); + if (error && error != -ENOENT) + return error; + + if (ts->gpiod_int && ts->gpiod_rst) { + /* reset the controller */ + error = goodix_reset(ts); + if (error) { + dev_err(&client->dev, "Controller reset failed.\n"); + return error; + } + } + goodix_read_config(ts); error = goodix_request_input_dev(ts, version_info, id_info); @@ -381,13 +508,13 @@ static int goodix_ts_probe(struct i2c_client *client, } static const struct i2c_device_id goodix_ts_id[] = { - { "GDIX1001:00", 0 }, + { "GDIX1001:00", (kernel_ulong_t)&goodix_gpio_rst_irq }, { } }; #ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { - { "GDIX1001", 0 }, + { "GDIX1001", (kernel_ulong_t)&goodix_gpio_rst_irq }, { } }; MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);