From patchwork Thu Jun 15 10:27:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 13281035 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 377C9C0015E for ; Thu, 15 Jun 2023 10:27:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245538AbjFOK1R (ORCPT ); Thu, 15 Jun 2023 06:27:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39174 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245424AbjFOK1N (ORCPT ); Thu, 15 Jun 2023 06:27:13 -0400 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 616A1271F for ; Thu, 15 Jun 2023 03:27:11 -0700 (PDT) Received: by mail-wr1-x42a.google.com with SMTP id ffacd0b85a97d-30fbf253dc7so473924f8f.0 for ; Thu, 15 Jun 2023 03:27:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1686824830; x=1689416830; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=9c2M/W71Umd5OR1G2L6k5M3nfF7xrs6GwHTTg7fiWIs=; b=Kn0DCJuy0jSPg3C4d5o4BQNBrg8ri2SZCAu9y1L/hKHfH+fo9LJ1xty8EXFCfWbkz1 lejgauIRcpHUUlIE+W+1+WE0eddPhG5HRBG4ny0WiiwCSGEMsf7WxqX4lMt6qczlCrne 5KwzVuhxUYhQyuyachYYm+pnQOe1He67JbbATxaQRIbGwwNQmwEr7lqOEeyzZc23ffxZ cWLs+WGYLXYB91GwOYnDUlr94xK+zPfeYxWdHazQ0GLdBVO7B6Pj2rvCfudIsNgu+ux0 XzLApMGCLsv2s7g6ESe95ApdtxWpvLFAVfFRRrRizr6UXYwzQQZ2aIOVn6MseH81UDp5 GAKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686824830; x=1689416830; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=9c2M/W71Umd5OR1G2L6k5M3nfF7xrs6GwHTTg7fiWIs=; b=JgNc0bxKsfnBsHHc/YXVoIJEimrgKM5Ue8IUV/TXhVcXMDvA+GfgftCLrQ6Rw7l75S BMdnPDQh5kuw0oHvuNqFUy1tmJcF04nEqxy4+9x8oCBqVM0glGCQx4Q2OuYihZl4aQB9 ejleHAV23HNyrWztvWx8Esl2MscpT1o1wr1qoa2NOxqBWjx6sHUqYhyF9vMeMSqmILA5 tJtI4WTA9dR2dkJR4qReSkJYttW6RJOyugN5u298Ulc+GYD62ZvEwaXZJ74tXKKWuOJh 5E2gwll0HUWXmRtMCt3EO+8ZAA8Ahg6Yo6rkUUtDjtDuiETrZHWd8VV0+OnK1uOGeMwg gdMQ== X-Gm-Message-State: AC+VfDycDlmYFojLKHgzd/ZIs03PtTw7BdU/y7YJ16dLa0XR/z97W6HK fczXV+EsENFfqrb21P8Xr0a4vg== X-Google-Smtp-Source: ACHHUZ5WnW6K6wJspp8ESkCXMlnFyQAYikTl8WVkPjrn1KuM+feUHP3nPhrgM38N21/EdO0DnNUFYw== X-Received: by 2002:adf:e54d:0:b0:311:19ad:a082 with SMTP id z13-20020adfe54d000000b0031119ada082mr645170wrm.3.1686824829831; Thu, 15 Jun 2023 03:27:09 -0700 (PDT) Received: from arrakeen.starnux.net ([2a01:e0a:982:cbb0:8261:5fff:fe11:bdda]) by smtp.gmail.com with ESMTPSA id u5-20020a5d5145000000b0030fa57d8064sm17332337wrt.52.2023.06.15.03.27.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Jun 2023 03:27:09 -0700 (PDT) From: Neil Armstrong Date: Thu, 15 Jun 2023 12:27:00 +0200 Subject: [PATCH v2 1/4] dt-bindings: input: document Goodix Berlin Touchscreen IC MIME-Version: 1.0 Message-Id: <20230606-topic-goodix-berlin-upstream-initial-v2-1-26bc8fe1e90e@linaro.org> References: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> In-Reply-To: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> To: Dmitry Torokhov , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bastien Nocera , Hans de Goede , Henrik Rydberg Cc: linux-input@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Neil Armstrong X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3049; i=neil.armstrong@linaro.org; h=from:subject:message-id; bh=pJJwmz5Q68XC8REHCc8ClhlwPyfSMUQlDbNdC2eJDX8=; b=owEBbQKS/ZANAwAKAXfc29rIyEnRAcsmYgBkiud6/CrkxC8xi4+BzQHlOhRQnGpyGT8hJ7TCeYjP 047zQw2JAjMEAAEKAB0WIQQ9U8YmyFYF/h30LIt33NvayMhJ0QUCZIrnegAKCRB33NvayMhJ0eNZEA CWflo7h8IIShUJsDgPRGAttJj691dePcGcV/Ges3E1uGEYf4G4Bl5MRPqCSfToAU03fGYQQJxn82Xg PtEDoeQK0pnle99FA7Wq1aUia2qWV2pflK37i2cs8cyVBe7PUOtD6P8a3TBN99TCmkGoMZjX+428du wvUPOM4pk2bOL1m0EXJpgT56GTczO2yVk16l7xFAF+3lMFVo+gEJksy7xPSfqltigHozXyEgqxwcCY cvwmOCdlUwlwWjIU3k5rE+A4cadpr9pzPD3JghHNtP0q62IBsD5UHwv8e21xL0/z0cz01KAZBzgKjl Tw1JVjABR479JTBYF46N8suVjWd1qS/LtfUWqmQ8YE3XS6jEOsNc9zswF8BTCgjuv/cJn+rYxUgeEV nIH3vbWbjd5VC4FHvqyvdkqMFtxBsfCrEj93h/AKE1lb+gGECRB4v5O1KX4npqsytIuWR+AxheVoh7 yUgfZ4DAHn9X2jR/eku/KeWsOXLI8kTns7FgHEF0oWFrUf8hQy5i8cTvi4nt3ABxIe0C+5xOXmhZz6 RX6bX42n7mJnrswghPqEds8THuhvbMmIjxn+xUK2TdEVca5oP4ZhFIEp2oxMpkTgltZtC2WpwubrpP kJglSEgR1zC4LIJ73oNjvRQK6D5PuN7vdXbZiyPCJSzbaWQE/DRAv29MPoYQ== X-Developer-Key: i=neil.armstrong@linaro.org; a=openpgp; fpr=89EC3D058446217450F22848169AB7B1A4CFF8AE Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Document the Goodix GT9916 wich is part of the "Berlin" serie of Touchscreen controllers IC from Goodix. Signed-off-by: Neil Armstrong Reviewed-by: Rob Herring --- .../bindings/input/touchscreen/goodix,gt9916.yaml | 95 ++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/goodix,gt9916.yaml b/Documentation/devicetree/bindings/input/touchscreen/goodix,gt9916.yaml new file mode 100644 index 000000000000..d90f045ac06c --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/goodix,gt9916.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/goodix,gt9916.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Goodix Berlin series touchscreen controller + +description: The Goodix Berlin series of touchscreen controllers + be connected to either I2C or SPI buses. + +maintainers: + - Neil Armstrong + +allOf: + - $ref: touchscreen.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +properties: + compatible: + enum: + - goodix,gt9916 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + reset-gpios: + maxItems: 1 + + avdd-supply: + description: Analog power supply regulator on AVDD pin + + vddio-supply: + description: power supply regulator on VDDIO pin + + spi-max-frequency: true + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-swapped-x-y: true + +additionalProperties: false + +required: + - compatible + - reg + - interrupts + - avdd-supply + - touchscreen-size-x + - touchscreen-size-y + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + touchscreen@5d { + compatible = "goodix,gt9916"; + reg = <0x5d>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + avdd-supply = <&ts_avdd>; + touchscreen-size-x = <1024>; + touchscreen-size-y = <768>; + }; + }; + - | + #include + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + num-cs = <1>; + cs-gpios = <&gpio 2 GPIO_ACTIVE_HIGH>; + touchscreen@0 { + compatible = "goodix,gt9916"; + reg = <0>; + interrupt-parent = <&gpio>; + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio1 1 GPIO_ACTIVE_LOW>; + avdd-supply = <&ts_avdd>; + spi-max-frequency = <1000000>; + touchscreen-size-x = <1024>; + touchscreen-size-y = <768>; + }; + }; + +... From patchwork Thu Jun 15 10:27:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 13281037 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4798DEB64D9 for ; Thu, 15 Jun 2023 10:27:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343716AbjFOK1U (ORCPT ); Thu, 15 Jun 2023 06:27:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39250 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245404AbjFOK1T (ORCPT ); Thu, 15 Jun 2023 06:27:19 -0400 Received: from mail-wm1-x32e.google.com (mail-wm1-x32e.google.com [IPv6:2a00:1450:4864:20::32e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F1BC02727 for ; Thu, 15 Jun 2023 03:27:12 -0700 (PDT) Received: by mail-wm1-x32e.google.com with SMTP id 5b1f17b1804b1-3f8d61cb36cso16909655e9.1 for ; Thu, 15 Jun 2023 03:27:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1686824831; x=1689416831; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=jajagWKtfaZySI2FZsCkEsGMMoObeBePAoORw5hV7F0=; b=Il3Aa0bCoGtw37uauhydiHm98oX2hB676kvha28vA4NpqTkalwiNSue+ONeK0CnxbD JZj63FMWuUWW/ofnclXbe70/VSwLICKyVNGdWrzFR9rbJ6cm06eyVlVa3dknCVd3r/0X c1+ETUf7DG3mDyJ/EimPuO5ktCkft8B24/0mq0CEvd8AahqxNXFNxV0WvSHbZLfGf+HF vBUVjOUr5gguA6bN7aCWgPN53xjgSnnVWXtsKCg+e/kqlDuR4i52fzzJjXXa4SwpBHl8 QLlI21UO1VhhhukZ4X6LxTvLP/gUymidrpXikye5frNkj+KOFwV4pUn6na8fUZNdGj5j HK3Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686824831; x=1689416831; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=jajagWKtfaZySI2FZsCkEsGMMoObeBePAoORw5hV7F0=; b=IWKFK7rHSuQghdhdNQQ/qBu+ECCZPj+qimicRLEMugThae1X8YiP+zM6jU/fQ7Xbbv Ta08hyRnoILBu13cezFe9sP8hFXe5cQAjEAY1V01uPpWlsUPgF60RoOiFh+AZVFlMxgn IiYic0PlAsRCWniw2D99+e5NcFGJRALM6sEdyS6LdN9enhlpvCTHe7JK3zDOOm74ja7t npH4fLP9l19Tscuy1lhfQEUBkKZYmtpmlH1enza9kXyG3e1AwxtrN7zmKRKPb9Ry/p8J jhUBNnRuiWcG63upfsWM/l13P+qQH5NyO6KGiq1xLkEU2qEsmI1d/aeEPRO9FBeHRNoq d83w== X-Gm-Message-State: AC+VfDwPieL+LfYRYcZk6nX1IfKOEf7Y2BoD2atEfyiSPfN3UDrLUSm/ px3e/zaBS1wlfOO3WcyjEZ7Jeg== X-Google-Smtp-Source: ACHHUZ6h4Xz1zM+b24UVBglSvF8YFbDzOM5rzejkKRgcE8kN0Grx2RwFvcP2ugbNRbLd1gRl3nBzgQ== X-Received: by 2002:a05:600c:211:b0:3f6:906:1195 with SMTP id 17-20020a05600c021100b003f609061195mr14081122wmi.35.1686824831088; Thu, 15 Jun 2023 03:27:11 -0700 (PDT) Received: from arrakeen.starnux.net ([2a01:e0a:982:cbb0:8261:5fff:fe11:bdda]) by smtp.gmail.com with ESMTPSA id u5-20020a5d5145000000b0030fa57d8064sm17332337wrt.52.2023.06.15.03.27.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Jun 2023 03:27:10 -0700 (PDT) From: Neil Armstrong Date: Thu, 15 Jun 2023 12:27:01 +0200 Subject: [PATCH v2 2/4] input: touchscreen: add core support for Goodix Berlin Touchscreen IC MIME-Version: 1.0 Message-Id: <20230606-topic-goodix-berlin-upstream-initial-v2-2-26bc8fe1e90e@linaro.org> References: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> In-Reply-To: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> To: Dmitry Torokhov , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bastien Nocera , Hans de Goede , Henrik Rydberg Cc: linux-input@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Neil Armstrong X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=25024; i=neil.armstrong@linaro.org; h=from:subject:message-id; bh=+ySkoQd8PzZ8Y7a52sr7pX8Ooep7RlfAdO67cRA8JNA=; b=owEBbQKS/ZANAwAKAXfc29rIyEnRAcsmYgBkiud6Ug5kaBeoRJxGIIH6o8x8kKssMBZq8ZAxT9cy Fy2LJYSJAjMEAAEKAB0WIQQ9U8YmyFYF/h30LIt33NvayMhJ0QUCZIrnegAKCRB33NvayMhJ0b4sD/ 45LGvLyCc0O/v51iToRs57hsERMIR7xrSF+k55Y8coYgo2a/XAMLelhosdFGNtzqIckH7MSaB5pNn8 ZHswuO9XXbz+NvJPc9Bwm04uROFsDJK+g4SY7swIDJP9lxxjkxu1zXb94ZiP6SjKUTP7Cv2yhaQq44 zwgUqhZV8g+54slfZYcCmYI/f4grVPzGbolILrYcSiT3ZrGN/pLTwOo2gGLX4bY8CuNAs1W9TtlYKW n/G4Xjx/hVV54m2azpSZPIpeGnJs7ulzxPnGq1TV+SI6AjPCRHVECnxQ4kT/PJgZ2HHjKwNdQ4Lp4V EyNpC6yz9u26A4R1V2vohWWpp8/wK1tD+ghFn0HfvK/S42VAjIuMtOF/Hfw4p1LG8jkbjxv1+nF9wY 6ditfX58e62lz6snhePiFZPMwt5ifKox51OzArzyRp+AFu9W9b+f86b5ZhNMFXNo1QkdOU3xiG5FPQ 5yosvp4ygjdmHxXtSnvlnpuYG0SaD8apVc4a/RsbIqe4LheNVtlhgDPEuJdzpbzTgoNNs+nFY9ZgKM urSFdr6w5/uvbBlBbe9WMkYW2N7q/NlXUcSBpLYRm+xNce7JZE/zqS+37O6V7quFSxfZmemCWyTfxG QZyU406LuomDeAXOGiGVp8t/spK1IHhZrXfws4j/1FcCbS3NGxU7I0t8dGPw== X-Developer-Key: i=neil.armstrong@linaro.org; a=openpgp; fpr=89EC3D058446217450F22848169AB7B1A4CFF8AE Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Add initial support for the new Goodix "Berlin" touchscreen ICs. These touchscreen ICs support SPI, I2C and I3C interface, up to 10 finger touch, stylus and gestures events. This initial driver is derived from the Goodix goodix_ts_berlin available at [1] and [2] and only supports the GT9916 IC present on the Qualcomm SM8550 MTP & QRD touch panel. The current implementation only supports BerlinD, aka GT9916. Support for advanced features like: - Firmware & config update - Stylus events - Gestures events - Previous revisions support (BerlinA or BerlinB) is not included in current version. The current support will work with currently flashed firmware and config, and bail out if firmware or config aren't flashed yet. [1] https://github.com/goodix/goodix_ts_berlin [2] https://git.codelinaro.org/clo/la/platform/vendor/opensource/touch-drivers Signed-off-by: Neil Armstrong --- drivers/input/touchscreen/Kconfig | 5 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/goodix_berlin.h | 178 +++++++ drivers/input/touchscreen/goodix_berlin_core.c | 681 +++++++++++++++++++++++++ 4 files changed, 865 insertions(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index c2cbd332af1d..1a6f6f6da991 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -416,6 +416,11 @@ config TOUCHSCREEN_GOODIX To compile this driver as a module, choose M here: the module will be called goodix. +config TOUCHSCREEN_GOODIX_BERLIN_CORE + depends on GPIOLIB || COMPILE_TEST + depends on REGMAP + tristate + config TOUCHSCREEN_HIDEEP tristate "HiDeep Touch IC" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 159cd5136fdb..29cdb042e104 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o +obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/goodix_berlin.h b/drivers/input/touchscreen/goodix_berlin.h new file mode 100644 index 000000000000..56c110d94dff --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Goodix Touchscreen Driver + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_berlin_berlin driver. + */ + +#ifndef __GOODIX_BERLIN_H_ +#define __GOODIX_BERLIN_H_ + +#include +#include +#include +#include + +#define GOODIX_MAX_TOUCH 10 + +#define GOODIX_NORMAL_RESET_DELAY_MS 100 + +#define MAX_SCAN_FREQ_NUM 8 +#define MAX_SCAN_RATE_NUM 8 +#define MAX_FREQ_NUM_STYLUS 8 + +#define IRQ_EVENT_HEAD_LEN 8 +#define BYTES_PER_POINT 8 +#define COOR_DATA_CHECKSUM_SIZE 2 + +#define GOODIX_TOUCH_EVENT BIT(7) +#define GOODIX_REQUEST_EVENT BIT(6) + +#define GOODIX_REQUEST_CODE_RESET 3 + +#define POINT_TYPE_STYLUS_HOVER 0x01 +#define POINT_TYPE_STYLUS 0x03 + +#define DEV_CONFIRM_VAL 0xAA +#define BOOTOPTION_ADDR 0x10000 +#define FW_VERSION_INFO_ADDR 0x10014 + +#define GOODIX_IC_INFO_MAX_LEN 1024 +#define GOODIX_IC_INFO_ADDR 0x10070 + +struct goodix_berlin_fw_version { + u8 rom_pid[6]; + u8 rom_vid[3]; + u8 rom_vid_reserved; + u8 patch_pid[8]; + u8 patch_vid[4]; + u8 patch_vid_reserved; + u8 sensor_id; + u8 reserved[2]; + u16 checksum; +} __packed; + +struct goodix_berlin_ic_info_version { + u8 info_customer_id; + u8 info_version_id; + u8 ic_die_id; + u8 ic_version_id; + u32 config_id; + u8 config_version; + u8 frame_data_customer_id; + u8 frame_data_version_id; + u8 touch_data_customer_id; + u8 touch_data_version_id; + u8 reserved[3]; +} __packed; + +struct goodix_berlin_ic_info_feature { + u16 freqhop_feature; + u16 calibration_feature; + u16 gesture_feature; + u16 side_touch_feature; + u16 stylus_feature; +} __packed; + +struct goodix_berlin_ic_info_misc { + u32 cmd_addr; + u16 cmd_max_len; + u32 cmd_reply_addr; + u16 cmd_reply_len; + u32 fw_state_addr; + u16 fw_state_len; + u32 fw_buffer_addr; + u16 fw_buffer_max_len; + u32 frame_data_addr; + u16 frame_data_head_len; + u16 fw_attr_len; + u16 fw_log_len; + u8 pack_max_num; + u8 pack_compress_version; + u16 stylus_struct_len; + u16 mutual_struct_len; + u16 self_struct_len; + u16 noise_struct_len; + u32 touch_data_addr; + u16 touch_data_head_len; + u16 point_struct_len; + u16 reserved1; + u16 reserved2; + u32 mutual_rawdata_addr; + u32 mutual_diffdata_addr; + u32 mutual_refdata_addr; + u32 self_rawdata_addr; + u32 self_diffdata_addr; + u32 self_refdata_addr; + u32 iq_rawdata_addr; + u32 iq_refdata_addr; + u32 im_rawdata_addr; + u16 im_readata_len; + u32 noise_rawdata_addr; + u16 noise_rawdata_len; + u32 stylus_rawdata_addr; + u16 stylus_rawdata_len; + u32 noise_data_addr; + u32 esd_addr; +} __packed; + +enum goodix_berlin_ts_event_type { + GOODIX_BERLIN_EVENT_INVALID, + GOODIX_BERLIN_EVENT_TOUCH, + GOODIX_BERLIN_EVENT_REQUEST, +}; + +enum goodix_berlin_ts_request_type { + GOODIX_BERLIN_REQUEST_TYPE_INVALID, + GOODIX_BERLIN_REQUEST_TYPE_RESET, +}; + +enum goodix_berlin_touch_point_status { + GOODIX_BERLIN_TS_NONE, + GOODIX_BERLIN_TS_TOUCH, +}; + +struct goodix_berlin_coords { + enum goodix_berlin_touch_point_status status; + unsigned int x, y, w, p; +}; + +struct goodix_berlin_touch_data { + int touch_num; + struct goodix_berlin_coords coords[GOODIX_MAX_TOUCH]; +}; + +struct goodix_berlin_event { + enum goodix_berlin_ts_event_type event_type; + enum goodix_berlin_ts_request_type request_code; + struct goodix_berlin_touch_data touch_data; +}; + +/* Runtime parameters extracted from goodix_berlin_ic_info */ +struct goodix_berlin_params { + u32 touch_data_addr; +}; + +struct goodix_berlin_core { + struct device *dev; + struct regmap *regmap; + struct regulator *avdd; + struct regulator *iovdd; + struct gpio_desc *reset_gpio; + struct touchscreen_properties props; + struct goodix_berlin_fw_version fw_version; + struct goodix_berlin_params params; + struct input_dev *input_dev; + struct goodix_berlin_event ts_event; + int irq; + struct dentry *debugfs_root; +}; + +int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, + struct regmap *regmap); + +extern const struct dev_pm_ops goodix_berlin_pm_ops; + +#endif diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c new file mode 100644 index 000000000000..11788662722a --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin_core.c @@ -0,0 +1,681 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Goodix Touchscreen Driver + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_ts_berlin driver. + */ +#include +#include +#include + +#include "goodix_berlin.h" + +/* + * Goodix "Berlin" Touchscreen ID driver + * + * Currently only handles Multitouch events with already + * programmed firmware and "config" for "Revision D" Berlin IC. + * + * Support is missing for: + * - ESD Management + * - Firmware update/flashing + * - "Config" update/flashing + * - Stylus Events + * - Gesture Events + * - Support for older revisions (A, B & C) + */ + +static bool goodix_berlin_check_checksum(const u8 *data, int size) +{ + u32 cal_checksum = 0; + u32 r_checksum = 0; + u32 i; + + if (size < COOR_DATA_CHECKSUM_SIZE) + return false; + + for (i = 0; i < size - COOR_DATA_CHECKSUM_SIZE; i++) + cal_checksum += data[i]; + + r_checksum += data[i++]; + r_checksum += (data[i] << 8); + + return (cal_checksum & 0xFFFF) == r_checksum; +} + +static bool goodix_berlin_is_dummy_data(struct goodix_berlin_core *cd, + const u8 *data, int size) +{ + int zero_count = 0; + int ff_count = 0; + int i; + + for (i = 0; i < size; i++) { + if (data[i] == 0) + zero_count++; + else if (data[i] == 0xff) + ff_count++; + } + if (zero_count == size || ff_count == size) { + dev_warn(cd->dev, "warning data is all %s\n", + zero_count == size ? "zero" : "0xff"); + return true; + } + + return false; +} + +static int goodix_berlin_dev_confirm(struct goodix_berlin_core *cd) +{ + u8 tx_buf[8], rx_buf[8]; + int retry = 3; + int error; + + memset(tx_buf, DEV_CONFIRM_VAL, sizeof(tx_buf)); + while (retry--) { + error = regmap_raw_write(cd->regmap, BOOTOPTION_ADDR, tx_buf, + sizeof(tx_buf)); + if (error < 0) + return error; + + error = regmap_raw_read(cd->regmap, BOOTOPTION_ADDR, rx_buf, + sizeof(rx_buf)); + if (error < 0) + return error; + + if (!memcmp(tx_buf, rx_buf, sizeof(tx_buf))) + return 0; + + usleep_range(5000, 5100); + } + + dev_err(cd->dev, "device confirm failed, rx_buf: %*ph\n", 8, rx_buf); + + return -EINVAL; +} + +static int goodix_berlin_power_on(struct goodix_berlin_core *cd, bool on) +{ + int error = 0; + + if (on) { + error = regulator_enable(cd->iovdd); + if (error < 0) { + dev_err(cd->dev, "Failed to enable iovdd: %d\n", error); + return error; + } + + /* Vendor waits 3ms for IOVDD to settle */ + usleep_range(3000, 3100); + + error = regulator_enable(cd->avdd); + if (error < 0) { + dev_err(cd->dev, "Failed to enable avdd: %d\n", error); + goto power_off_iovdd; + } + + /* Vendor waits 15ms for IOVDD to settle */ + usleep_range(15000, 15100); + + gpiod_set_value(cd->reset_gpio, 0); + + /* Vendor waits 4ms for Firmware to initialize */ + usleep_range(4000, 4100); + + error = goodix_berlin_dev_confirm(cd); + if (error < 0) + goto power_off_gpio; + + /* Vendor waits 100ms for Firmware to fully boot */ + msleep(GOODIX_NORMAL_RESET_DELAY_MS); + + return 0; + } + +power_off_gpio: + gpiod_set_value(cd->reset_gpio, 1); + + regulator_disable(cd->avdd); + +power_off_iovdd: + regulator_disable(cd->iovdd); + + return error; +} + +static int goodix_berlin_read_version(struct goodix_berlin_core *cd) +{ + u8 buf[sizeof(struct goodix_berlin_fw_version)]; + int retry = 2; + int error; + + while (retry--) { + error = regmap_raw_read(cd->regmap, FW_VERSION_INFO_ADDR, buf, sizeof(buf)); + if (error) { + dev_dbg(cd->dev, "read fw version: %d, retry %d\n", error, retry); + usleep_range(5000, 5100); + continue; + } + + if (goodix_berlin_check_checksum(buf, sizeof(buf))) + break; + + dev_dbg(cd->dev, "invalid fw version: checksum error\n"); + + error = -EINVAL; + + /* Do not sleep on the last try */ + if (retry) + usleep_range(10000, 11000); + } + + if (error) { + dev_err(cd->dev, "failed to get fw version"); + return error; + } + + memcpy(&cd->fw_version, buf, sizeof(cd->fw_version)); + + return 0; +} + +/* Only extract necessary data for runtime */ +static int goodix_berlin_convert_ic_info(struct goodix_berlin_core *cd, + const u8 *data, u16 length) +{ + struct goodix_berlin_ic_info_misc misc; + unsigned int offset = 0; + u8 param_num; + + offset += sizeof(__le16); /* length */ + offset += sizeof(struct goodix_berlin_ic_info_version); + offset += sizeof(struct goodix_berlin_ic_info_feature); + + /* goodix_berlin_ic_info_param, variable width structure */ + offset += 4 * sizeof(u8); /* drv_num, sen_num, button_num, force_num */ + + if (offset >= length) + goto invalid_offset; + + param_num = data[offset++]; /* active_scan_rate_num */ + + offset += param_num * sizeof(__le16); + + if (offset >= length) + goto invalid_offset; + + param_num = data[offset++]; /* mutual_freq_num*/ + + offset += param_num * sizeof(__le16); + + if (offset >= length) + goto invalid_offset; + + param_num = data[offset++]; /* self_tx_freq_num */ + + offset += param_num * sizeof(__le16); + + if (offset >= length) + goto invalid_offset; + + param_num = data[offset++]; /* self_rx_freq_num */ + + offset += param_num * sizeof(__le16); + + if (offset >= length) + goto invalid_offset; + + param_num = data[offset++]; /* stylus_freq_num */ + + offset += param_num * sizeof(__le16); + + if (offset + sizeof(misc) > length) + goto invalid_offset; + + /* goodix_berlin_ic_info_misc */ + memcpy(&misc, &data[offset], sizeof(misc)); + + cd->params.touch_data_addr = le32_to_cpu(misc.touch_data_addr); + + return 0; + +invalid_offset: + dev_err(cd->dev, "ic_info length is invalid (offset %d length %d)\n", + offset, length); + return -EINVAL; +} + +static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd) +{ + int error, i; + u16 length = 0; + u32 ic_addr; + u8 afe_data[GOODIX_IC_INFO_MAX_LEN] = { 0 }; + + ic_addr = GOODIX_IC_INFO_ADDR; + + for (i = 0; i < 3; i++) { + error = regmap_raw_read(cd->regmap, ic_addr, (u8 *)&length, sizeof(length)); + if (error) { + dev_info(cd->dev, "failed get ic info length, %d\n", error); + usleep_range(5000, 5100); + continue; + } + + length = le16_to_cpu(length); + if (length >= GOODIX_IC_INFO_MAX_LEN) { + dev_info(cd->dev, "invalid ic info length %d, retry %d\n", length, i); + continue; + } + + error = regmap_raw_read(cd->regmap, ic_addr, afe_data, length); + if (error) { + dev_info(cd->dev, "failed get ic info data, %d\n", error); + usleep_range(5000, 5100); + continue; + } + + /* check whether the data is valid (ex. bus default values) */ + if (goodix_berlin_is_dummy_data(cd, (const uint8_t *)afe_data, length)) { + dev_info(cd->dev, "fw info data invalid\n"); + usleep_range(5000, 5100); + continue; + } + + if (!goodix_berlin_check_checksum((const uint8_t *)afe_data, length)) { + dev_info(cd->dev, "fw info checksum error\n"); + usleep_range(5000, 5100); + continue; + } + + break; + } + if (i == 3) { + dev_err(cd->dev, "failed get ic info\n"); + return -EINVAL; + } + + error = goodix_berlin_convert_ic_info(cd, afe_data, length); + if (error) { + dev_err(cd->dev, "error converting ic info\n"); + return error; + } + + /* check some key info */ + if (!cd->params.touch_data_addr) { + dev_err(cd->dev, "touch_data_addr is null\n"); + return -EINVAL; + } + + return 0; +} + +static int goodix_berlin_after_event_handler(struct goodix_berlin_core *cd) +{ + u8 sync_clean = 0; + + return regmap_raw_write(cd->regmap, cd->params.touch_data_addr, &sync_clean, 1); +} + +static void goodix_berlin_parse_finger(struct goodix_berlin_core *cd, + struct goodix_berlin_touch_data *touch_data, + u8 *buf, int touch_num) +{ + unsigned int id = 0, x = 0, y = 0, w = 0; + u8 *coor_data; + int i; + + coor_data = &buf[IRQ_EVENT_HEAD_LEN]; + + for (i = 0; i < touch_num; i++) { + id = (coor_data[0] >> 4) & 0x0F; + + if (id >= GOODIX_MAX_TOUCH) { + dev_warn(cd->dev, "invalid finger id %d\n", id); + + touch_data->touch_num = 0; + return; + } + + x = le16_to_cpup((__le16 *)(coor_data + 2)); + y = le16_to_cpup((__le16 *)(coor_data + 4)); + w = le16_to_cpup((__le16 *)(coor_data + 6)); + + touch_data->coords[id].status = GOODIX_BERLIN_TS_TOUCH; + touch_data->coords[id].x = x; + touch_data->coords[id].y = y; + touch_data->coords[id].w = w; + + coor_data += BYTES_PER_POINT; + } + + touch_data->touch_num = touch_num; +} + +static int goodix_berlin_touch_handler(struct goodix_berlin_core *cd, + u8 *pre_buf, u32 pre_buf_len) +{ + static u8 buffer[IRQ_EVENT_HEAD_LEN + BYTES_PER_POINT * GOODIX_MAX_TOUCH + 2]; + struct goodix_berlin_touch_data *touch_data = &cd->ts_event.touch_data; + u8 point_type = 0; + u8 touch_num = 0; + int error = 0; + + memset(&cd->ts_event, 0, sizeof(cd->ts_event)); + + /* copy pre-data to buffer */ + memcpy(buffer, pre_buf, pre_buf_len); + + touch_num = buffer[2] & 0x0F; + + if (touch_num > GOODIX_MAX_TOUCH) { + dev_warn(cd->dev, "invalid touch num %d\n", touch_num); + return -EINVAL; + } + + /* read more data if more than 2 touch events */ + if (unlikely(touch_num > 2)) { + error = regmap_raw_read(cd->regmap, + cd->params.touch_data_addr + pre_buf_len, + &buffer[pre_buf_len], + (touch_num - 2) * BYTES_PER_POINT); + if (error) { + dev_err(cd->dev, "failed get touch data\n"); + return error; + } + } + + goodix_berlin_after_event_handler(cd); + + if (!touch_num) + goto out_touch_handler; + + point_type = buffer[IRQ_EVENT_HEAD_LEN] & 0x0F; + + if (point_type == POINT_TYPE_STYLUS || point_type == POINT_TYPE_STYLUS_HOVER) { + dev_warn_once(cd->dev, "Stylus event type not handled\n"); + return 0; + } + + if (!goodix_berlin_check_checksum(&buffer[IRQ_EVENT_HEAD_LEN], + touch_num * BYTES_PER_POINT + 2)) { + dev_dbg(cd->dev, "touch data checksum error\n"); + dev_dbg(cd->dev, "data: %*ph\n", + touch_num * BYTES_PER_POINT + 2, &buffer[IRQ_EVENT_HEAD_LEN]); + return -EINVAL; + } + +out_touch_handler: + cd->ts_event.event_type = GOODIX_BERLIN_EVENT_TOUCH; + goodix_berlin_parse_finger(cd, touch_data, buffer, touch_num); + + return 0; +} + +static int goodix_berlin_event_handler(struct goodix_berlin_core *cd) +{ + int pre_read_len; + u8 pre_buf[32]; + u8 event_status; + int error; + + pre_read_len = IRQ_EVENT_HEAD_LEN + BYTES_PER_POINT * 2 + + COOR_DATA_CHECKSUM_SIZE; + + error = regmap_raw_read(cd->regmap, cd->params.touch_data_addr, pre_buf, + pre_read_len); + if (error) { + dev_err(cd->dev, "failed get event head data\n"); + return error; + } + + if (pre_buf[0] == 0x00) + return -EINVAL; + + if (!goodix_berlin_check_checksum(pre_buf, IRQ_EVENT_HEAD_LEN)) { + dev_warn(cd->dev, "touch head checksum err : %*ph\n", + IRQ_EVENT_HEAD_LEN, pre_buf); + return -EINVAL; + } + + event_status = pre_buf[0]; + if (event_status & GOODIX_TOUCH_EVENT) + return goodix_berlin_touch_handler(cd, pre_buf, pre_read_len); + + if (event_status & GOODIX_REQUEST_EVENT) { + cd->ts_event.event_type = GOODIX_BERLIN_EVENT_REQUEST; + if (pre_buf[2] == GOODIX_REQUEST_CODE_RESET) + cd->ts_event.request_code = GOODIX_BERLIN_REQUEST_TYPE_RESET; + else + dev_warn(cd->dev, "unsupported request code 0x%x\n", pre_buf[2]); + } + + goodix_berlin_after_event_handler(cd); + + return 0; +} + +static void goodix_berlin_report_finger(struct goodix_berlin_core *cd) +{ + struct goodix_berlin_touch_data *touch_data = &cd->ts_event.touch_data; + int i; + + mutex_lock(&cd->input_dev->mutex); + + for (i = 0; i < GOODIX_MAX_TOUCH; i++) { + bool pressed = touch_data->coords[i].status == GOODIX_BERLIN_TS_TOUCH; + + input_mt_slot(cd->input_dev, i); + input_mt_report_slot_state(cd->input_dev, MT_TOOL_FINGER, pressed); + + if (touch_data->coords[i].status == GOODIX_BERLIN_TS_TOUCH) { + dev_dbg(cd->dev, "report: id[%d], x %d, y %d, w %d\n", i, + touch_data->coords[i].x, + touch_data->coords[i].y, + touch_data->coords[i].w); + + touchscreen_report_pos(cd->input_dev, &cd->props, + touch_data->coords[i].x, + touch_data->coords[i].y, true); + input_report_abs(cd->input_dev, ABS_MT_TOUCH_MAJOR, + touch_data->coords[i].w); + } + } + + input_mt_sync_frame(cd->input_dev); + input_sync(cd->input_dev); + + mutex_unlock(&cd->input_dev->mutex); +} + +static int goodix_berlin_request_handle(struct goodix_berlin_core *cd) +{ + /* TOFIX: Handle more request codes */ + if (cd->ts_event.request_code != GOODIX_BERLIN_REQUEST_TYPE_RESET) { + dev_info(cd->dev, "can't handle request type 0x%x\n", + cd->ts_event.request_code); + return -EINVAL; + } + + gpiod_set_value(cd->reset_gpio, 1); + usleep_range(2000, 2100); + gpiod_set_value(cd->reset_gpio, 0); + + msleep(GOODIX_NORMAL_RESET_DELAY_MS); + + return 0; +} + +static irqreturn_t goodix_berlin_threadirq_func(int irq, void *data) +{ + struct goodix_berlin_core *cd = data; + int error; + + error = goodix_berlin_event_handler(cd); + if (likely(!error)) { + switch (cd->ts_event.event_type) { + case GOODIX_BERLIN_EVENT_TOUCH: + goodix_berlin_report_finger(cd); + break; + + case GOODIX_BERLIN_EVENT_REQUEST: + goodix_berlin_request_handle(cd); + break; + + /* TOFIX: Handle more request types */ + case GOODIX_BERLIN_EVENT_INVALID: + break; + } + } + + return IRQ_HANDLED; +} + +static int goodix_berlin_input_dev_config(struct goodix_berlin_core *cd, + const struct input_id *id) +{ + struct input_dev *input_dev; + int error; + + input_dev = devm_input_allocate_device(cd->dev); + if (!input_dev) + return -ENOMEM; + + cd->input_dev = input_dev; + input_set_drvdata(input_dev, cd); + + input_dev->name = "Goodix Berlin Capacitive TouchScreen"; + input_dev->phys = "input/ts"; + input_dev->dev.parent = cd->dev; + + memcpy(&input_dev->id, id, sizeof(*id)); + + /* Set input parameters */ + input_set_abs_params(cd->input_dev, ABS_MT_POSITION_X, 0, SZ_64K - 1, 0, 0); + input_set_abs_params(cd->input_dev, ABS_MT_POSITION_Y, 0, SZ_64K - 1, 0, 0); + input_set_abs_params(cd->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + + touchscreen_parse_properties(cd->input_dev, true, &cd->props); + + error = input_mt_init_slots(cd->input_dev, GOODIX_MAX_TOUCH, INPUT_MT_DIRECT); + if (error) + return error; + + return input_register_device(cd->input_dev); +} + +static int goodix_berlin_pm_suspend(struct device *dev) +{ + struct goodix_berlin_core *cd = dev_get_drvdata(dev); + + disable_irq(cd->irq); + + return goodix_berlin_power_on(cd, false); +} + +static int goodix_berlin_pm_resume(struct device *dev) +{ + struct goodix_berlin_core *cd = dev_get_drvdata(dev); + int error; + + error = goodix_berlin_power_on(cd, true); + if (error) + return error; + + enable_irq(cd->irq); + + return 0; +} + +EXPORT_GPL_SIMPLE_DEV_PM_OPS(goodix_berlin_pm_ops, + goodix_berlin_pm_suspend, + goodix_berlin_pm_resume); + +static void goodix_berlin_power_off(void *data) +{ + struct goodix_berlin_core *cd = data; + + goodix_berlin_power_on(cd, false); +} + +int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id, + struct regmap *regmap) +{ + struct goodix_berlin_core *cd; + int error; + + if (irq <= 0) + return -EINVAL; + + cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL); + if (!cd) + return -ENOMEM; + + cd->dev = dev; + cd->regmap = regmap; + cd->irq = irq; + + cd->reset_gpio = devm_gpiod_get_optional(cd->dev, "reset", GPIOF_OUT_INIT_HIGH); + if (IS_ERR(cd->reset_gpio)) + return dev_err_probe(cd->dev, PTR_ERR(cd->reset_gpio), + "Failed to request reset gpio\n"); + + cd->avdd = devm_regulator_get(cd->dev, "avdd"); + if (IS_ERR(cd->avdd)) + return dev_err_probe(cd->dev, PTR_ERR(cd->avdd), + "Failed to request avdd regulator\n"); + + cd->iovdd = devm_regulator_get(cd->dev, "iovdd"); + if (IS_ERR(cd->iovdd)) + return dev_err_probe(cd->dev, PTR_ERR(cd->iovdd), + "Failed to request iovdd regulator\n"); + + error = goodix_berlin_input_dev_config(cd, id); + if (error < 0) { + dev_err(cd->dev, "failed set input device"); + return error; + } + + error = devm_request_threaded_irq(dev, irq, NULL, + goodix_berlin_threadirq_func, + IRQF_ONESHOT, "goodix-berlin", cd); + if (error) { + dev_err(dev, "request threaded irq failed: %d\n", error); + return error; + } + + dev_set_drvdata(dev, cd); + + error = goodix_berlin_power_on(cd, true); + if (error) { + dev_err(cd->dev, "failed power on"); + return error; + } + + error = devm_add_action_or_reset(dev, goodix_berlin_power_off, cd); + if (error) + return error; + + error = goodix_berlin_read_version(cd); + if (error < 0) { + dev_err(cd->dev, "failed to get version info"); + return error; + } + + error = goodix_berlin_get_ic_info(cd); + if (error) { + dev_err(cd->dev, "invalid ic info, abort"); + return error; + } + + dev_dbg(cd->dev, "Goodix Berlin %s Touchscreen Controller", cd->fw_version.patch_pid); + + return 0; +} +EXPORT_SYMBOL_GPL(goodix_berlin_probe); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Goodix Berlin Core Touchscreen driver"); +MODULE_AUTHOR("Neil Armstrong "); From patchwork Thu Jun 15 10:27:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 13281036 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A3F8EB64DD for ; Thu, 15 Jun 2023 10:27:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S245263AbjFOK1V (ORCPT ); Thu, 15 Jun 2023 06:27:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39226 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244229AbjFOK1R (ORCPT ); Thu, 15 Jun 2023 06:27:17 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B4B9010F7 for ; Thu, 15 Jun 2023 03:27:13 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id ffacd0b85a97d-30e412a852dso5670721f8f.0 for ; Thu, 15 Jun 2023 03:27:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1686824832; x=1689416832; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=w/VIsWWHYp9W1vsM/zTQjB7ygwb8WPrDQ9hfnQ47tKA=; b=fsYkmU9ESYYZLv/ex7nVF9LAj7zxKMMU+1UgX4+t5cuaodlaA5cN2k6wZp2Ioj6jBI PEjiHQ8rbNpkoz4IOPrzv409lyX52SvIXy7AmKsCpd7R77n76ThFVApzpGFUx6CC2xJM g0e+17xrLAnfbNPRGQhI6grBMsViq10NPOBS4JFxHUIOOwp6nH6frVN+2IxUe72HtyHi Rwr9/DSfeH9fskFsX6gKg5uniAo2u3p+nc6iEH3pY8Xp47LErcI+x255kBYwZZ3eoQ2j sKlhn0749i2hcpEZrxQSjB7rx8y+oYKWW/xfbW1G64K1mPVh7IHW2/K140MARPxWeNCu Y2rQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686824832; x=1689416832; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=w/VIsWWHYp9W1vsM/zTQjB7ygwb8WPrDQ9hfnQ47tKA=; b=GqvOLFjmq9qzmxrHAHW1+C1uEIvY6p2o7Fg11smBEcSFEmd94iAbpJjTi984+pK/mT nhf/JvoNLPUtzzg0mrnuh9FmrOF6870iiUoujAZr2Hcd9EAEx2holhd2CII4e9Yt8ovK Js86wym/kKCclUSX3kwVp5DmKVS+19I4h2Ju2YuX7WP26t8URyYPTHQBPyFe6X0qndrW 1u/PkBrjLjcvU37GSBqfs6P8Qf8yDp5gjznW6O+albbqZ2EG8a3fbiB/OPZiW6yM40+k fTABb0EnlT3hUb0UP6tseCtQOctblBcK8wRdDO0z8uIA12IMnNloYrVLBblKVrLiTIhd IRjQ== X-Gm-Message-State: AC+VfDwnm3RgPp8tn0yYmUJdGN6HzcpdhSYTk40mczpAtVKIoFW6cta4 Z5W4wMckdaYSxL996k7He/hrpA== X-Google-Smtp-Source: ACHHUZ4Z3dfoqzO93CMCBVn9xc2hjY17iLqoybHqyN2roabaE0UC9Jkmn3fvLyqLeANNWz1qGYphHQ== X-Received: by 2002:a5d:6991:0:b0:30a:e378:76e with SMTP id g17-20020a5d6991000000b0030ae378076emr9457432wru.64.1686824832139; Thu, 15 Jun 2023 03:27:12 -0700 (PDT) Received: from arrakeen.starnux.net ([2a01:e0a:982:cbb0:8261:5fff:fe11:bdda]) by smtp.gmail.com with ESMTPSA id u5-20020a5d5145000000b0030fa57d8064sm17332337wrt.52.2023.06.15.03.27.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Jun 2023 03:27:11 -0700 (PDT) From: Neil Armstrong Date: Thu, 15 Jun 2023 12:27:02 +0200 Subject: [PATCH v2 3/4] input: touchscreen: add I2C support for Goodix Berlin Touchscreen IC MIME-Version: 1.0 Message-Id: <20230606-topic-goodix-berlin-upstream-initial-v2-3-26bc8fe1e90e@linaro.org> References: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> In-Reply-To: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> To: Dmitry Torokhov , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bastien Nocera , Hans de Goede , Henrik Rydberg Cc: linux-input@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Neil Armstrong X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4427; i=neil.armstrong@linaro.org; h=from:subject:message-id; bh=QHOGGZ9YgSGmH3eo15UAb80SbAazpeBZYECMck5eCmA=; b=owEBbQKS/ZANAwAKAXfc29rIyEnRAcsmYgBkiud6fvco9i4cWpbxTrvClLAkjjDr+LnoqR4/2T7T Oqc8mXeJAjMEAAEKAB0WIQQ9U8YmyFYF/h30LIt33NvayMhJ0QUCZIrnegAKCRB33NvayMhJ0XVmEA CSKJsHHh2rykXQIJQnTFYIlYmVrlEH1JzWVtI3NncnZmadvG+Y235qJ/UoYDCUZOUuyVAam5N8q9Vd KAZRW5UHRcMP48/cIC2InZjGF8HbDmMCzlSZMsw+XDfxmSVsliAf46tSQTIhZuFsVmf1iTQiDpF57N rZiMtrRv/D164Qj8bhj5FQt88rOkiVkY8eX4A7bZWiylBoyo1xj4VmwZf/zGPxeCau9eyVIPwTeXJe KbQF5qcXza8m2QSFGrxjjZ+rEvzOjX0vavFGw6YD6Kc+azSZacTTifiNt9sQVrTWECdRlGQIQd0U1+ iJNm47io2e+voAh+msvUojqVUIzhEm7weBkJSTaUg2z5C5NBBdHWIJ0mupZUaMa7VOlaNqk5DQ+ocE S0Un9sh47XDoCtjA9bHg6GT7H+ev26tThQWgejJpixJIYyrWlQC2Qz3WTgBgo8lvYreNLe7UIS8Ufo aOrz16MTZDW9Vkl6PNZ0pie3ip4RzZBaBIl2o1dv4O9P5Do/u2USg/85W0kQvLOY1EYHxjC+SoZMZv vDF8ONWpQ8LSBG1hc/yRWWpuMotAbRXdfeHTL2YnTP7nBYJtzCt3jQsJz78UY81kX2adK63+q7IZdz H4ZiWUyPWNzkXYtrkHuPHhwM1qUW1V4hS9ipz6vactGhgKkjYcoNffbkS0KQ== X-Developer-Key: i=neil.armstrong@linaro.org; a=openpgp; fpr=89EC3D058446217450F22848169AB7B1A4CFF8AE Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Add initial support for the new Goodix "Berlin" touchscreen ICs over the I2C interface. This initial driver is derived from the Goodix goodix_ts_berlin available at [1] and [2] and only supports the GT9916 IC present on the Qualcomm SM8550 MTP & QRD touch panel. The current implementation only supports BerlinD, aka GT9916. [1] https://github.com/goodix/goodix_ts_berlin [2] https://git.codelinaro.org/clo/la/platform/vendor/opensource/touch-drivers Signed-off-by: Neil Armstrong --- drivers/input/touchscreen/Kconfig | 14 ++++++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/goodix_berlin_i2c.c | 69 +++++++++++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1a6f6f6da991..5e21cca6025d 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -421,6 +421,20 @@ config TOUCHSCREEN_GOODIX_BERLIN_CORE depends on REGMAP tristate +config TOUCHSCREEN_GOODIX_BERLIN_I2C + tristate "Goodix Berlin I2C touchscreen" + depends on I2C + depends on REGMAP_I2C + select TOUCHSCREEN_GOODIX_BERLIN_CORE + help + Say Y here if you have a Goodix Berlin IC connected to + your system via I2C. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called goodix_berlin_i2c. + config TOUCHSCREEN_HIDEEP tristate "HiDeep Touch IC" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 29cdb042e104..921a2da0c2be 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o +obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/goodix_berlin_i2c.c b/drivers/input/touchscreen/goodix_berlin_i2c.c new file mode 100644 index 000000000000..6407b2258eb1 --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin_i2c.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Goodix Berlin Touchscreen Driver + * + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_ts_berlin driver. + */ +#include +#include +#include +#include + +#include "goodix_berlin.h" + +#define I2C_MAX_TRANSFER_SIZE 256 + +static const struct regmap_config goodix_berlin_i2c_regmap_conf = { + .reg_bits = 32, + .val_bits = 8, + .max_raw_read = I2C_MAX_TRANSFER_SIZE, + .max_raw_write = I2C_MAX_TRANSFER_SIZE, +}; + +/* vendor & product left unassigned here, should probably be updated from fw info */ +static const struct input_id goodix_berlin_i2c_input_id = { + .bustype = BUS_I2C, +}; + +static int goodix_berlin_i2c_probe(struct i2c_client *client) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(client, &goodix_berlin_i2c_regmap_conf); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return goodix_berlin_probe(&client->dev, client->irq, + &goodix_berlin_i2c_input_id, regmap); +} + +static const struct i2c_device_id goodix_berlin_i2c_id[] = { + { "gt9916", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id); + +static const struct of_device_id goodix_berlin_i2c_of_match[] = { + { .compatible = "goodix,gt9916", }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match); + +static struct i2c_driver goodix_berlin_i2c_driver = { + .driver = { + .name = "goodix-berlin-i2c", + .of_match_table = goodix_berlin_i2c_of_match, + .pm = pm_sleep_ptr(&goodix_berlin_pm_ops), + }, + .probe = goodix_berlin_i2c_probe, + .id_table = goodix_berlin_i2c_id, +}; +module_i2c_driver(goodix_berlin_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Goodix Berlin I2C Touchscreen driver"); +MODULE_AUTHOR("Neil Armstrong "); From patchwork Thu Jun 15 10:27:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Neil Armstrong X-Patchwork-Id: 13281038 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D2FC7C0015E for ; Thu, 15 Jun 2023 10:27:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239201AbjFOK1W (ORCPT ); Thu, 15 Jun 2023 06:27:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39254 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S245461AbjFOK1T (ORCPT ); Thu, 15 Jun 2023 06:27:19 -0400 Received: from mail-lj1-x22c.google.com (mail-lj1-x22c.google.com [IPv6:2a00:1450:4864:20::22c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA404212A for ; Thu, 15 Jun 2023 03:27:14 -0700 (PDT) Received: by mail-lj1-x22c.google.com with SMTP id 38308e7fff4ca-2b4420a8c44so10723381fa.2 for ; Thu, 15 Jun 2023 03:27:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1686824833; x=1689416833; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=8ybjd+QrBvVu0zDRNg4Z7l4eXFNbVwdU/ccLoGQD+UU=; b=PraZBEsIv2ndh/VAfL+yzPSyodzZU5F33StuNRdOgWmWp3EphYnK9qGr1dvTjWQ4IC BzWYedH9lh7/+chaOuIAgcjv7eJmq6TKd/0t1Ya7x3VcZEz4kIilSGyMDqbSGnLfUCNl geVY9VyJDKHgIm6aLiwM3JLiCH6x+L6FBIduuN0krgUTCn9MwFeEyPb2CxOrNXs41ZkF l5fPdeF1dU3rYZ1bJFvUI1OlHdmVqfrdcy9sifcJp9MAEUBSaFp8pu+dYFNlLFG85vgz yfejVkjZKJSPiOtB8vhVGpsi/KCcyxnhs4DMLafCVftBfqBaak5TIUpa+ip4MkbUA3ec AvqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686824833; x=1689416833; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8ybjd+QrBvVu0zDRNg4Z7l4eXFNbVwdU/ccLoGQD+UU=; b=HS4ebP4EZXhtiLcupnPQP9cRj6RCgJ8zSvuqts6LM0FGFFSjLivCTiW9FrTMkwjuNT iMCH5GhY8/fm2KmcD5rLLyaEFgrJNpa3NYUOv4QqGiypJUQVcYU1WOBTz/5g4Fj1013f vhLnOh3iN6e3iIRU1UnF/QJnHR/49uEvbxMzUgmMlAGWKWTHisa9/QXuKybDSTD9z7ne UQ4k/WmvvReUz1KRxafQPj1tCoxMbBU4eLtW1suwroNWOa1RBH4Y35lQNmlEaxilCgt2 L0Rw8LlOCm+TgBFrMQBx0Urd6TFL+4f365I4JFQJt55BKVx6GvTd1tF1ZrPAHLcALqKJ ey+g== X-Gm-Message-State: AC+VfDxfaT+vTfxthH317sBEXdzCcNhAB110I5EBFfQIS1uVdTXFvG/F egBCvA5/GEGxr1cnMtF6grX72A== X-Google-Smtp-Source: ACHHUZ7qeAJcv5BFQS0XYgCKkX1aZG4grPmZB98hbmT/omgQXZSZ6UKCcP8FIakHdb897dKAHzTH7A== X-Received: by 2002:a19:6d1c:0:b0:4f6:424c:4fa8 with SMTP id i28-20020a196d1c000000b004f6424c4fa8mr8736851lfc.17.1686824833128; Thu, 15 Jun 2023 03:27:13 -0700 (PDT) Received: from arrakeen.starnux.net ([2a01:e0a:982:cbb0:8261:5fff:fe11:bdda]) by smtp.gmail.com with ESMTPSA id u5-20020a5d5145000000b0030fa57d8064sm17332337wrt.52.2023.06.15.03.27.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 15 Jun 2023 03:27:12 -0700 (PDT) From: Neil Armstrong Date: Thu, 15 Jun 2023 12:27:03 +0200 Subject: [PATCH v2 4/4] input: touchscreen: add SPI support for Goodix Berlin Touchscreen IC MIME-Version: 1.0 Message-Id: <20230606-topic-goodix-berlin-upstream-initial-v2-4-26bc8fe1e90e@linaro.org> References: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> In-Reply-To: <20230606-topic-goodix-berlin-upstream-initial-v2-0-26bc8fe1e90e@linaro.org> To: Dmitry Torokhov , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Bastien Nocera , Hans de Goede , Henrik Rydberg Cc: linux-input@vger.kernel.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Neil Armstrong X-Mailer: b4 0.12.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7579; i=neil.armstrong@linaro.org; h=from:subject:message-id; bh=M9Fcb2iZK373bguA+9fk5ubbR87iAMaN2qDGauqltKw=; b=owEBbQKS/ZANAwAKAXfc29rIyEnRAcsmYgBkiud7lyWVyYJVEyeKyBFPvd4pUOtGXU32o0vVILXx CgV0G/SJAjMEAAEKAB0WIQQ9U8YmyFYF/h30LIt33NvayMhJ0QUCZIrnewAKCRB33NvayMhJ0VnqD/ 9N6ChGooUY0+tNEH3tDsGm0iuu3pzYn7ALlfW9ygFkWfNhl1GI5v/es5iRy/HjRTE5k9207MGdMXvQ VIHCZsAcqVp9kJRbQ6SIkZKiteXEeLb0XUurCsmb4ZScyh0P/aqX1qi1z/5YJ6NlPMPNDmZRMpmLzo YTjAt+f448wWBI9pXyCJWwvF1Mk99RvFqyye8vVj1MTZfxhWXD6iXyyWU/NS3jOvYgqaPS1yr5gvhG eutzpyV+wJQmONmmNTamT98UDDtAfCFAfyq5YV/QA80dAaEYI0WQjZwW8S6QnGxNzRDztsGgR5+4o6 GwzDORj3iH4RrYB6YMi0GRr4HK2bKVIbRjCF/uYsyIEetQkDeBkUBkqi7DwPWbnkSHXyvSb/+MLU0v TuYttB1MxarlqLKNefEMFKZscRZLBi2d+cVLQhG/n5lBLtysESisb4kToVZQOdPDzfWiBLLoU15tuU 06ImYR5/G+Q5zLaGTeg3yemGonCe5uvJv22EkicmroXIOBn61fFnwGJCSPMgRfzjnEi65HX3dPY/ty /VZ2CbR8vCiBrHLZ4kYERY0OGKhvpR+2DfdMzTc/l0VStbiX36G40DSFSBMn33WlGcp6GwG4+DANm2 v9ENovCUeZJ4820MrvOeLlELF6CbzVNaCcUSAo3mnSwumGnBuHPCnaBexxag== X-Developer-Key: i=neil.armstrong@linaro.org; a=openpgp; fpr=89EC3D058446217450F22848169AB7B1A4CFF8AE Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org Add initial support for the new Goodix "Berlin" touchscreen ICs over the SPI interface. The driver doesn't use the regmap_spi code since the SPI messages needs to be prefixed, thus this custom regmap code. This initial driver is derived from the Goodix goodix_ts_berlin available at [1] and [2] and only supports the GT9916 IC present on the Qualcomm SM8550 MTP & QRD touch panel. The current implementation only supports BerlinD, aka GT9916. [1] https://github.com/goodix/goodix_ts_berlin [2] https://git.codelinaro.org/clo/la/platform/vendor/opensource/touch-drivers Signed-off-by: Neil Armstrong --- drivers/input/touchscreen/Kconfig | 13 ++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/goodix_berlin_spi.c | 172 ++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 5e21cca6025d..2d86615e5090 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -435,6 +435,19 @@ config TOUCHSCREEN_GOODIX_BERLIN_I2C To compile this driver as a module, choose M here: the module will be called goodix_berlin_i2c. +config TOUCHSCREEN_GOODIX_BERLIN_SPI + tristate "Goodix Berlin SPI touchscreen" + depends on SPI_MASTER + select TOUCHSCREEN_GOODIX_BERLIN_CORE + help + Say Y here if you have a Goodix Berlin IC connected to + your system via SPI. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called goodix_berlin_spi. + config TOUCHSCREEN_HIDEEP tristate "HiDeep Touch IC" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 921a2da0c2be..29524e8a83db 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o +obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o diff --git a/drivers/input/touchscreen/goodix_berlin_spi.c b/drivers/input/touchscreen/goodix_berlin_spi.c new file mode 100644 index 000000000000..3a1bc251b32d --- /dev/null +++ b/drivers/input/touchscreen/goodix_berlin_spi.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Goodix Berlin Touchscreen Driver + * + * Copyright (C) 2020 - 2021 Goodix, Inc. + * Copyright (C) 2023 Linaro Ltd. + * + * Based on goodix_ts_berlin driver. + */ +#include +#include +#include +#include +#include + +#include "goodix_berlin.h" + +#define SPI_TRANS_PREFIX_LEN 1 +#define REGISTER_WIDTH 4 +#define SPI_READ_DUMMY_LEN 3 +#define SPI_READ_PREFIX_LEN (SPI_TRANS_PREFIX_LEN + REGISTER_WIDTH + SPI_READ_DUMMY_LEN) +#define SPI_WRITE_PREFIX_LEN (SPI_TRANS_PREFIX_LEN + REGISTER_WIDTH) + +#define SPI_WRITE_FLAG 0xF0 +#define SPI_READ_FLAG 0xF1 + +static int goodix_berlin_spi_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, + size_t val_size) +{ + struct spi_device *spi = context; + struct spi_transfer xfers; + struct spi_message spi_msg; + const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */ + u8 *buf; + int ret; + + if (reg_size != REGISTER_WIDTH) + return -EINVAL; + + buf = kzalloc(SPI_READ_PREFIX_LEN + val_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + spi_message_init(&spi_msg); + memset(&xfers, 0, sizeof(xfers)); + + /* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */ + buf[0] = SPI_READ_FLAG; + put_unaligned_be32(*reg, buf + SPI_TRANS_PREFIX_LEN); + memset(buf + SPI_TRANS_PREFIX_LEN + REGISTER_WIDTH, 0xff, + SPI_READ_DUMMY_LEN); + + xfers.tx_buf = buf; + xfers.rx_buf = buf; + xfers.len = SPI_READ_PREFIX_LEN + val_size; + xfers.cs_change = 0; + spi_message_add_tail(&xfers, &spi_msg); + + ret = spi_sync(spi, &spi_msg); + if (ret < 0) + dev_err(&spi->dev, "transfer error:%d", ret); + else + memcpy(val_buf, buf + SPI_READ_PREFIX_LEN, val_size); + + kfree(buf); + return ret; +} + +static int goodix_berlin_spi_write(void *context, const void *data, + size_t count) +{ + unsigned int len = count - REGISTER_WIDTH; + struct spi_device *spi = context; + struct spi_transfer xfers; + struct spi_message spi_msg; + const u32 *reg = data; /* reg is stored as native u32 at start of buffer */ + u8 *buf; + int ret; + + buf = kzalloc(SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + spi_message_init(&spi_msg); + memset(&xfers, 0, sizeof(xfers)); + + buf[0] = SPI_WRITE_FLAG; + put_unaligned_be32(*reg, buf + SPI_TRANS_PREFIX_LEN); + memcpy(buf + SPI_WRITE_PREFIX_LEN, data + REGISTER_WIDTH, len); + + xfers.tx_buf = buf; + xfers.len = SPI_WRITE_PREFIX_LEN + len; + xfers.cs_change = 0; + spi_message_add_tail(&xfers, &spi_msg); + + ret = spi_sync(spi, &spi_msg); + if (ret < 0) + dev_err(&spi->dev, "transfer error:%d", ret); + + kfree(buf); + return ret; +} + +static const struct regmap_config goodix_berlin_spi_regmap_conf = { + .reg_bits = 32, + .val_bits = 8, + .read = goodix_berlin_spi_read, + .write = goodix_berlin_spi_write, +}; + +/* vendor & product left unassigned here, should probably be updated from fw info */ +static const struct input_id goodix_berlin_spi_input_id = { + .bustype = BUS_SPI, +}; + +static int goodix_berlin_spi_probe(struct spi_device *spi) +{ + struct regmap_config *regmap_config; + struct regmap *regmap; + size_t max_size; + int error = 0; + + regmap_config = devm_kmemdup(&spi->dev, &goodix_berlin_spi_regmap_conf, + sizeof(*regmap_config), GFP_KERNEL); + if (!regmap_config) + return -ENOMEM; + + spi->mode = SPI_MODE_0; + spi->bits_per_word = 8; + error = spi_setup(spi); + if (error) + return error; + + max_size = spi_max_transfer_size(spi); + regmap_config->max_raw_read = max_size - SPI_READ_PREFIX_LEN; + regmap_config->max_raw_write = max_size - SPI_WRITE_PREFIX_LEN; + + regmap = devm_regmap_init(&spi->dev, NULL, spi, regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return goodix_berlin_probe(&spi->dev, spi->irq, + &goodix_berlin_spi_input_id, regmap); +} + +static const struct spi_device_id goodix_berlin_spi_ids[] = { + { "gt9916" }, + { }, +}; +MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids); + +static const struct of_device_id goodix_berlin_spi_of_match[] = { + { .compatible = "goodix,gt9916", }, + { } +}; +MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match); + +static struct spi_driver goodix_berlin_spi_driver = { + .driver = { + .name = "goodix-berlin-spi", + .of_match_table = goodix_berlin_spi_of_match, + .pm = pm_sleep_ptr(&goodix_berlin_pm_ops), + }, + .probe = goodix_berlin_spi_probe, + .id_table = goodix_berlin_spi_ids, +}; +module_spi_driver(goodix_berlin_spi_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Goodix Berlin SPI Touchscreen driver"); +MODULE_AUTHOR("Neil Armstrong ");