From nobody Sun Feb 8 14:22:01 2026 Received: from eu-smtp-delivery-101.mimecast.com (eu-smtp-delivery-101.mimecast.com [185.58.86.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1F6DD2D7DD9 for ; Thu, 22 Jan 2026 12:49:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.58.86.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769086193; cv=none; b=fFvsTi0SCFe9vrGXuATkr1G2rb/XtZ8o4uvcI8NPkLrWMH6Ob8zfb+O0SVMN9OEllTeaFKCjekWFjgCXQOO9dGHsMpLuDQ67yS6xxZhStpBruGrAB0AlDZYdGqDLjENorz+ixF/NRoqzMVqHRK2dOTNY57g9oHgvH/IXVs670bM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769086193; c=relaxed/simple; bh=6SwBFIzoAvyd6PedNOXfyh0xiT0W+ooeNO88QPYIEmE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hXzC+QDR/bBIPvY/U5RcX1JB6M5nMe79XmNhuqeaK4Ih2dplo8L36eXVlRTPwwgjP4R1IOAuwL3YM9OwLEHV7BsBBZHIYeIwb3PKrzTIhixUOhEuq7KZxZHwBrtVDUsmyKFLD2e4IYaHRUNpnCJW+2mvuKoI85vpilB3vLI1BcE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=touchnetix.com; spf=pass smtp.mailfrom=touchnetix.com; arc=none smtp.client-ip=185.58.86.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=touchnetix.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=touchnetix.com Received: from LO2P265CU024.outbound.protection.outlook.com (mail-uksouthazon11021097.outbound.protection.outlook.com [52.101.95.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id uk-mta-11-XIkvaretNb-YmThZZ8NSNw-1; Thu, 22 Jan 2026 12:48:37 +0000 X-MC-Unique: XIkvaretNb-YmThZZ8NSNw-1 X-Mimecast-MFC-AGG-ID: XIkvaretNb-YmThZZ8NSNw_1769086117 Received: from LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:e9::9) by LOAP123MB8292.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:43b::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.11; Thu, 22 Jan 2026 12:48:36 +0000 Received: from LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM ([fe80::4a94:a629:f86f:40d1]) by LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM ([fe80::4a94:a629:f86f:40d1%4]) with mapi id 15.20.9542.009; Thu, 22 Jan 2026 12:48:36 +0000 From: AThomas63 To: dmitry.torokhov@gmail.com CC: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, mark.satterthwaite@touchnetix.com, andrew.thomas@touchnetix.com, m.felsch@pengutronix.de, kamel.bouhara@bootlin.com Subject: [PATCH 1/1] Adding support for aXiom touchscreen controller Date: Thu, 22 Jan 2026 12:48:19 +0000 Message-ID: <20260122124819.273188-2-andrew.thomas@touchnetix.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260122124819.273188-1-andrew.thomas@touchnetix.com> References: <20260122124819.273188-1-andrew.thomas@touchnetix.com> X-ClientProxiedBy: LO4P265CA0031.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:2ae::7) To LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:e9::9) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: LOYP123MB2701:EE_|LOAP123MB8292:EE_ X-MS-Office365-Filtering-Correlation-Id: 9029e896-46da-40ca-23e1-08de59b48ed8 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|52116014|376014|1800799024|366016|38350700014|18082099003 X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?YvXZp1IFemgkhDxPOJz9q21TUYR+U+q/hLqboIXt1I4/HNTgKonrYVIx14gx?= =?us-ascii?Q?djKxVtIxR5bucFKRtfY2qVF9Llu0HM2ipurpdJ+eC/keBGMfQ93NcT8o3UH7?= =?us-ascii?Q?j+iU2+mBMckhmkA1Z7bKxaEtsjkD8xEC5SQbXH+fxdfwq3UZ++7M1BobTL1l?= =?us-ascii?Q?3/ZafPRxtmoAiNTWTf8BF60dRhTJBbc7C/ne9qHzUtzCpkk+roGBjtXb/yhE?= =?us-ascii?Q?r6QIZCOrgTYZNMslQuxHLC3WXjANuRXmNZfWgGrA7Svb2ZDGztEvDaPDt0Jo?= =?us-ascii?Q?vIr/Giw8WRmUFJdd57/Dd7oOzro8a9XvA6o9NiXtWY6gb339mdPluaBYWvNk?= =?us-ascii?Q?fhUJT8aLjSv6bcwePzNcz2otEaCagi6k0e1Qh7Qpz0QRTY4++2YBJ3zRxfKn?= =?us-ascii?Q?yNdJoHNCBgPQc9xUqiS9B6giN/S6gTCluwcVng4WrjagQACI9CtUMMokOmPA?= =?us-ascii?Q?B49cv01VwDWMPXlLMBLGdsrUxw8mhC8l90/Epo7uEyqJ+ifGqM2QhKV89ejL?= =?us-ascii?Q?l0BQVimBPtAFWjbSd78EuXGO/rpneVyZ5PjRcNJRsJVr1YDdtBZqpXeKobJF?= =?us-ascii?Q?vyjKKXc/nIHzclz0fXM9gXLRJJiNYwXkKe1TVCMqT0ET6F7x5DEtl/2lKuhg?= =?us-ascii?Q?fTgiF+hajdiLK/tEYhwG5RQp1swprbVb7tn05Bj2TXuqkyodHuUUsB+XIMBy?= =?us-ascii?Q?QU1jlWkIvFtTkujmd3XWVTkFmZccQAm1rrw8kyZQe73pqpZyKPt9bXQxf0bQ?= =?us-ascii?Q?tsL298aVZ8129XNEk8sBI00WiFRDrg4sffnxfFICa+77I0P3LQR9yJs3eXsQ?= =?us-ascii?Q?pPAa2/eBel4p3eu32JJ6IYhmMW7tB2lWQ+q9CrZoTurg2gCw56Q/B8iyCYCb?= =?us-ascii?Q?I3yXGKa87coTjJnjpNCHrUX0e6c3JPxEGEN9NC5WQmd8aLz1VnMUfU9ekUKq?= =?us-ascii?Q?OZySjfp3gsSqN66YawsdcY9TyTUDI6ByN80pTtbHtqfcP3bkHm4gPAFCrNVQ?= =?us-ascii?Q?7plCKyYjudHlFakUAW9JgQ60K6HEdgqjrgKKlz26MSH1Y6RuweUBzHL1ew6m?= =?us-ascii?Q?9YVa4iKERUBsNqie0LAp9wgRvIRP3CCAz37eBO7Wxres6pjJSeFwGzK6nC3P?= =?us-ascii?Q?llnYFZioDD7fx72Sez93UnSoLXkGmx9IMK7AC1WmIZd1t5yylZC89CukGe8i?= =?us-ascii?Q?qB/tMtpH7gfkHTypB72JWzWBTsg6RJ/WPgADQ93OgfGPYC54v3aA+KmK11G2?= =?us-ascii?Q?qj6/l0sQq3H+xebTMdzrhU7XkaLKc+Z9lrX6TPVtqenw6lPqXCyh2VrOodCc?= =?us-ascii?Q?aLXSm7qK8kJbMLVikjF4k/xRgMmqodYn67hdgLYYvCY+T82H4BKfj1MrvOlp?= =?us-ascii?Q?6qwfb7o8KbCragba92DYkWpeTSi8SQuYgLGt9flaNT3dAnnZvZOpkdBBbc1v?= =?us-ascii?Q?fGTpEa9iyr7okioYajKxSRxxjdcFCi+2pR5jFzeHAL0OjvS/ALLUwZNfO4z/?= =?us-ascii?Q?zDfxC066kugccCwh1SsMUbWf0f6zdJy5cJ2tM/zkXYiiQ+6FFfJrLCBw1vya?= =?us-ascii?Q?H6AplQ8NJ8MaMQwvh0FgQe0Sd5DqYdTLzL2yqcUZbPScN0qXd7DWcDI0LNCM?= =?us-ascii?Q?KO7bYmwXDwII2m7Jbpd56Xg=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(52116014)(376014)(1800799024)(366016)(38350700014)(18082099003);DIR:OUT;SFP:1102 X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?cCm1JeMyuxcjumJa6AIKAS/CgEdqz9XJAX5fHcwpXv6y+BKAv5QDVLxj4HBi?= =?us-ascii?Q?R8gKLhub3PbxF+g5WS9tpVMPKC24fPc1ZC46SIlJ/NrXdqeeWsR+4mWQJN6r?= =?us-ascii?Q?OFKEZef32N/9EpYBh0TGprKDsPlFnY/YrVAL5TG/qoIO3qJsWZAJGJ1OI0dY?= =?us-ascii?Q?qc4ecwBXb6gC5isr0MMje+wgKeub2Zn9Ffp6+xX4500ERb6TiWC4oT9PBP6f?= =?us-ascii?Q?s9/f+uj7OCAr82p15ipGor0UTACYqsj48GDesN68TjRaC9Zy85jHkiC5DAPA?= =?us-ascii?Q?6baKYkRUskfutjYc9JN01GmdpH13am9NvjC9qIDRXBkFpOWJ2oU+Tu0jrVvp?= =?us-ascii?Q?w+Ph18U2B99iNt9rHZixIukl30Q+HDgJuObTP3vDNvhDWiErhK7X1+BKEKJQ?= =?us-ascii?Q?qYtDci12HqqYkFcgVbTG86yDSa4gMpi6nM6nN5wEFOZuz3txGm97yR88Dsjb?= =?us-ascii?Q?xb4Lrik4qrR0kfSJig3OdNoFGZEFJenF01KmTMPVboIJlvGmkZGcZZ8ZIEdW?= =?us-ascii?Q?gFKGHgsDFUhYPe8I9jfdKYi/vupFgZZlaaEb0oDQmtb9CJX+xlvNlcGPR9uE?= =?us-ascii?Q?dPHLut4T053AFDx3d+oL8WpOOWM5vKAYKFNOMTdVayhEuLlXU21v+FLxG1z/?= =?us-ascii?Q?N7ZtCV8QSZlfJc8c/BtEWtyvHFFhACcvTyuN/2Kk+fbkgtwwLNTLFOSV7vdX?= =?us-ascii?Q?9MaVtAtTDeKOaadC/8wnVomGji7ua88GWCCLyO3jZV8wWwiYDHj03ZnKvYxK?= =?us-ascii?Q?K7M4l6EB0cwW2SZsXPUvx036rcFcsp5gkfr3+lDd3Sg/UZcPOIXiSbXGhta2?= =?us-ascii?Q?F22HXTbBG3hNe1mEY7QcblkejChklDLDKOiE9n7WbengnrjRsn4hPUdg3Zji?= =?us-ascii?Q?6sVLSS0XN7SJOtiYuz07mZWz/oMekKu8q/R8BDEexYEPPpuzuOc8NUmBLTi4?= =?us-ascii?Q?1+yOiwuSgMbFcJbaQ6hn2MS3M0OOnxZN3Z4PWiFJsKGqo2LFVghQoJydUZjE?= =?us-ascii?Q?KbzIUOByZFi4qQq5LXZZypBW8NMJ86twshPxJ2wmfPRu2g5ZZSxX5ZPvt+0g?= =?us-ascii?Q?8CUK5aCqMpxRmLEQX/MsxBlh5qQ632pu4CyhuyuqD4BIi75fH8i/mCWyt7Px?= =?us-ascii?Q?+7vNUwP2PisMd0BzOuYe5t7LR+eB26ji7B21cQTi6iSZ0/KGNuVlFtEEASzs?= =?us-ascii?Q?WetRImiZ0wbecxlAl0JcpGlGrtczxZCtLJS93W44IbhC3vdOpXL6q1+U79du?= =?us-ascii?Q?7pqeaTqMhDFXKMyVe/BozOmRm29I6/0kh2APT65wKxUGUkwccNNTDWxl9lZJ?= =?us-ascii?Q?+4WSOXFaIJBfD9cvq4fElKTq7PTq1GgR0TV8zpxd+JoACiRzJilDB/o5Gm9Q?= =?us-ascii?Q?1h7yetBDrEc6MwVQlF/IY/vXE48NmJVUgoy8RIBdocb2YvBnzr/++3UQCksJ?= =?us-ascii?Q?KM25N3pAHtn9KqQexgH5gi5NFmqW3+FJrUDsZPOlG3wpyVAbmL8Trn5Vg585?= =?us-ascii?Q?P1Rmo45CP7+z/g1bcpQi44UF1VW3fbQbPRG+HDudWfjACzZIdHwoLYOLtnyH?= =?us-ascii?Q?fbFHveczDCERNhx0gqOQ/wjcm0jhBeIDn/VRwcpweyTKuQKSbt+kZX89+8m3?= =?us-ascii?Q?kYQGYRyGONzvsF2CFqus31neRQoNMFpIyvk2UEWzbBg5kzBMBuBD9rpbPNKh?= =?us-ascii?Q?gb3YWuPThKGzfoZOp585fU1fvqaO0F4pB9/sSWUxJvous4wVwXJn7D6A4PNw?= =?us-ascii?Q?wmEsh6dKe0GXF0bl2qoJSaOQKOVso5Y=3D?= X-OriginatorOrg: touchnetix.com X-MS-Exchange-CrossTenant-Network-Message-Id: 9029e896-46da-40ca-23e1-08de59b48ed8 X-MS-Exchange-CrossTenant-AuthSource: LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Jan 2026 12:48:35.9926 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 120474da-7cc3-44b9-aff9-438a33341070 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: yddozgPypgaHESzoIE2I0V59K+2HF6eFyGPC+E8rGadOiko7s88zHxvT3SY0zge29sA26Dd7gFaqt4+J9ff/VbMo4F5vLTXcqMqvSWJSUYg= X-MS-Exchange-Transport-CrossTenantHeadersStamped: LOAP123MB8292 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: m7fpM2juFSMNS7Ak37LzYBjsqdsXYA3SDylWi053RTo_1769086117 X-Mimecast-Originator: touchnetix.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Signed-off-by: AThomas63 --- drivers/input/touchscreen/Kconfig | 30 ++ drivers/input/touchscreen/Makefile | 3 + drivers/input/touchscreen/axiom_core.c | 482 +++++++++++++++++++++++++ drivers/input/touchscreen/axiom_core.h | 128 +++++++ drivers/input/touchscreen/axiom_i2c.c | 152 ++++++++ drivers/input/touchscreen/axiom_spi.c | 159 ++++++++ 6 files changed, 954 insertions(+) create mode 100644 drivers/input/touchscreen/axiom_core.c create mode 100644 drivers/input/touchscreen/axiom_core.h create mode 100644 drivers/input/touchscreen/axiom_i2c.c create mode 100644 drivers/input/touchscreen/axiom_spi.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/= Kconfig index 7d5b72ee07fa..f2b4fb317bdd 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -162,6 +162,36 @@ config TOUCHSCREEN_AUO_PIXCIR To compile this driver as a module, choose M here: the module will be called auo-pixcir-ts. =20 +config TOUCHSCREEN_AXIOM_CORE + tristate "TouchNetix Axiom touchscreen" + help + Say Y here if you have an Axiom touchscreen connected + to your system. You will also need to select appropriate + bus connection below. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called axiom_core. + +config TOUCHSCREEN_AXIOM_I2C + tristate "support I2C bus connection" + depends on TOUCHSCREEN_AXIOM_CORE && I2C + help + Say Y here if the touchscreen is connected via I2C bus. + + To compile this driver as a module, choose M here: the + module will be called axiom_spi. + +config TOUCHSCREEN_AXIOM_SPI + tristate "support SPI bus connection" + depends on TOUCHSCREEN_AXIOM_CORE && SPI + help + Say Y here if the touchscreen is connected via SPI bus. + + To compile this driver as a module, choose M here: the + module will be called axiom_spi. + config TOUCHSCREEN_BU21013 tristate "BU21013 based touch panel controllers" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen= /Makefile index ab9abd151078..9b7d572c4589 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -19,6 +19,9 @@ obj-$(CONFIG_TOUCHSCREEN_APPLE_Z2) +=3D apple_z2.o obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) +=3D ar1021_i2c.o obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) +=3D atmel_mxt_ts.o obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) +=3D auo-pixcir-ts.o +obj-$(CONFIG_TOUCHSCREEN_AXIOM_CORE) +=3D axiom_core.o +obj-$(CONFIG_TOUCHSCREEN_AXIOM_I2C) +=3D axiom_i2c.o +obj-$(CONFIG_TOUCHSCREEN_AXIOM_SPI) +=3D axiom_spi.o obj-$(CONFIG_TOUCHSCREEN_BU21013) +=3D bu21013_ts.o obj-$(CONFIG_TOUCHSCREEN_BU21029) +=3D bu21029_ts.o obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8318) +=3D chipone_icn8318.o diff --git a/drivers/input/touchscreen/axiom_core.c b/drivers/input/touchsc= reen/axiom_core.c new file mode 100644 index 000000000000..7983effe40f7 --- /dev/null +++ b/drivers/input/touchscreen/axiom_core.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2020-2026 TouchNetix Ltd. + * + * Author(s): Mark Satterthwaite + * Pedro Torruella + * Bart Prescott + * Hannah Rossiter + * Andrew Thomas + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +// #define DEBUG // Enable debug messages + +#include +#include +#include +#include +#include +#include +#include "axiom_core.h" + +/* u31 device info masks */ +#define AX_DEV_ID_MASK GENMASK(14, 0) +#define AX_MODE BIT(15) +#define AX_FW_REV_MINOR_MASK GENMASK(7, 0) +#define AX_FW_REV_MAJOR_MASK GENMASK(15, 8) +#define AX_VARIANT_MASK GENMASK(5, 0) +#define AX_FW_STATUS BIT(7) +#define AX_TCP_REV_MASK GENMASK(15, 8) +#define AX_BOOT_REV_MINOR_MASK GENMASK(7, 0) +#define AX_BOOT_REV_MAJOR_MASK GENMASK(15, 8) +#define AX_NUM_USAGES_MASK GENMASK(7, 0) +#define AX_SILICON_REV_MASK GENMASK(11, 8) +#define AX_RUNTIME_FW_PATCH_MASK GENMASK(15, 12) + +/* u31 usage table entry masks */ +#define AX_U31_USAGE_NUM_MASK GENMASK(7, 0) +#define AX_U31_START_PAGE_MASK GENMASK(15, 8) +#define AX_U31_NUM_PAGES_MASK GENMASK(7, 0) +#define AX_U31_MAX_OFFSET_MASK GENMASK(14, 8) +#define AX_U31_OFFSET_TYPE_BIT BIT(15) +#define AX_U31_UIF_REV_MASK GENMASK(7, 0) +#define AX_U31_USAGE_TYPE_MASK GENMASK(15, 8) + +/* u34 report masks */ +#define AX_U34_LEN_MASK GENMASK(6, 0) +#define AX_U34_OVERFLOW BIT(7) +#define AX_U34_USAGE_MASK GENMASK(15, 8) +#define AX_U34_PAYLOAD_BUFFER 2 + +/* u41 report masks */ +#define AX_U41_PRESENT_MASK GENMASK(9, 0) +#define U41_X_Y_OFFSET (2) +#define U41_COORD_SIZE (4) +#define U41_Z_OFFSET (42) + +static const char *const fw_variants[] =3D { "3D", "2D", "FORCE", + "0D", "XL", "TOUCHPAD" }; + +static int axiom_set_capabilities(struct input_dev *input_dev) +{ + input_dev->name =3D "TouchNetix aXiom Touchscreen"; + input_dev->phys =3D "input/axiom_ts"; + + // Single Touch + input_set_abs_params(input_dev, ABS_X, 0, 65535, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 65535, 0, 0); + + // Multi Touch + // Min, Max, Fuzz (expected noise in px, try 4?) and Flat + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, 65535, 0, 0); + // Min, Max, Fuzz (expected noise in px, try 4?) and Flat + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 65535, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); + input_set_abs_params(input_dev, ABS_MT_DISTANCE, 0, 127, 0, 0); + input_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 127, 0, 0); + + input_mt_init_slots(input_dev, U41_MAX_TARGETS, INPUT_MT_DIRECT); + + return 0; +} + +static struct u31_usage_entry *usage_find_entry(struct axiom *ax, u16 usag= e) +{ + u16 i; + + for (i =3D 0; i < ax->dev_info.num_usages; i++) { + if (ax->usage_table[i].usage_num =3D=3D usage) + return &ax->usage_table[i]; + } + + pr_err("aXiom-core: Usage u%02x not found in usage table\n", usage); + return ERR_PTR(-EINVAL); +} + +static void axiom_unpack_device_info(const u8 *buf, + struct axiom_device_info *info) +{ + u16 w; + + w =3D get_unaligned_le16(buf); + info->device_id =3D FIELD_GET(AX_DEV_ID_MASK, w); + info->mode =3D !!(w & AX_MODE); + + w =3D get_unaligned_le16(buf + 2); + info->runtime_fw_rev_minor =3D FIELD_GET(AX_FW_REV_MINOR_MASK, w); + info->runtime_fw_rev_major =3D FIELD_GET(AX_FW_REV_MAJOR_MASK, w); + + w =3D get_unaligned_le16(buf + 4); + info->device_build_variant =3D FIELD_GET(AX_VARIANT_MASK, w); + info->runtime_fw_status =3D !!(w & AX_FW_STATUS); + info->tcp_revision =3D FIELD_GET(AX_TCP_REV_MASK, w); + + w =3D get_unaligned_le16(buf + 6); + info->bootloader_fw_rev_minor =3D FIELD_GET(AX_BOOT_REV_MINOR_MASK, w); + info->bootloader_fw_rev_major =3D FIELD_GET(AX_BOOT_REV_MAJOR_MASK, w); + + info->jedec_id =3D get_unaligned_le16(buf + 8); + + w =3D get_unaligned_le16(buf + 10); + info->num_usages =3D FIELD_GET(AX_NUM_USAGES_MASK, w); + info->silicon_revision =3D FIELD_GET(AX_SILICON_REV_MASK, w); + info->runtime_fw_rev_patch =3D FIELD_GET(AX_RUNTIME_FW_PATCH_MASK, w); +} + +static void axiom_unpack_usage_table(u8 *buf, struct axiom *ax) +{ + u8 *ptr; + struct u31_usage_entry *entry; + int i; + u16 w; + u16 report_len; + + for (i =3D 0; i < ax->dev_info.num_usages && i < U31_MAX_USAGES; i++) { + entry =3D &ax->usage_table[i]; + /* Calculate offset for this specific entry */ + ptr =3D buf + (i * SIZE_U31_USAGE_ENTRY); + + w =3D get_unaligned_le16(ptr); + entry->usage_num =3D FIELD_GET(AX_U31_USAGE_NUM_MASK, w); + entry->start_page =3D FIELD_GET(AX_U31_START_PAGE_MASK, w); + + w =3D get_unaligned_le16(ptr + 2); + entry->num_pages =3D FIELD_GET(AX_U31_NUM_PAGES_MASK, w); + entry->max_offset =3D FIELD_GET(AX_U31_MAX_OFFSET_MASK, w); + entry->offset_type =3D !!(w & AX_U31_OFFSET_TYPE_BIT); + + w =3D get_unaligned_le16(ptr + 4); + entry->uifrevision =3D FIELD_GET(AX_U31_UIF_REV_MASK, w); + entry->usage_type =3D FIELD_GET(AX_U31_USAGE_TYPE_MASK, w); + + // Convert words to bytes + report_len =3D (entry->max_offset + 1) * 2; + if ((entry->usage_type =3D=3D REPORT) && + (report_len > ax->max_report_len)) { + ax->max_report_len =3D report_len; + } + } +} + +static int axiom_init_dev_info(struct axiom *ax) +{ + int i; + struct u31_usage_entry *u; + int err; + const char *variant_str; + + /* Read page 0 of u31 */ + err =3D ax->bus_ops->read(ax->dev, 0x0, SIZE_U31_DEVICE_INFO, + ax->read_buf); + if (err) + return -EIO; + + axiom_unpack_device_info(ax->read_buf, &ax->dev_info); + + if (ax->dev_info.device_build_variant < ARRAY_SIZE(fw_variants)) { + variant_str =3D fw_variants[ax->dev_info.device_build_variant]; + } else { + variant_str =3D "UNKNOWN"; + } + char silicon_rev =3D (char)(0x41 + ax->dev_info.silicon_revision); + + dev_info(ax->dev, "Firmware Info:\n"); + dev_info(ax->dev, " BL Mode : %u\n", ax->dev_info.mode); + dev_info(ax->dev, " Device ID : %04x\n", ax->dev_info.device_id); + dev_info(ax->dev, " FW Revision : %u.%u.%u-%s %s\n", + ax->dev_info.runtime_fw_rev_major, + ax->dev_info.runtime_fw_rev_minor, + ax->dev_info.runtime_fw_rev_patch, + (ax->dev_info.runtime_fw_status =3D=3D 0) ? "eng" : "prod", + variant_str); + dev_info(ax->dev, " BL Revision : %02x.%02x\n", + ax->dev_info.bootloader_fw_rev_major, + ax->dev_info.bootloader_fw_rev_minor); + dev_info(ax->dev, " Silicon : 0x%04X (Rev %c)\n", + ax->dev_info.jedec_id, silicon_rev); + dev_info(ax->dev, " Num Usages : %u\n", ax->dev_info.num_usages); + + if (ax->dev_info.num_usages > U31_MAX_USAGES) { + dev_err(ax->dev, + "Num usages (%u) exceeds maximum supported (%u)\n", + ax->dev_info.num_usages, U31_MAX_USAGES); + return -EINVAL; + } + + /* Read the second page of u31 to get the usage table */ + err =3D ax->bus_ops->read(ax->dev, 0x100, + sizeof(ax->usage_table[0]) * + ax->dev_info.num_usages, + ax->read_buf); + if (err) + return -EIO; + + axiom_unpack_usage_table(ax->read_buf, ax); + + dev_info(ax->dev, "Usage Table:\n"); + for (i =3D 0; i < ax->dev_info.num_usages; i++) { + u =3D &ax->usage_table[i]; + + dev_info( + ax->dev, + " Usage: u%02x Rev: %3u Page: 0x%02x00 Num Pages: %3u\n", + u->usage_num, u->uifrevision, u->start_page, + u->num_pages); + } + dev_info(ax->dev, "Max Report Length: %u\n", ax->max_report_len); + + if (ax->max_report_len > AXIOM_MAX_READ_SIZE) { + dev_err(ax->dev, + "aXiom maximum report length (%u) greater than allocated buffer size (%= u).", + ax->max_report_len, AXIOM_MAX_READ_SIZE); + return -EINVAL; + } + + /* Set u34 address to allow direct access to report reading address */ + u =3D usage_find_entry(ax, 0x34); + if (IS_ERR(u)) + return PTR_ERR(u); + ax->u34_address =3D u->start_page << 8; + + return 0; +} + +static int axiom_process_u41_report(struct axiom *ax, u8 *report) +{ + int i; + u16 target_present; + bool active; + u8 offset; + enum u41_target_state_e state; + u16 x; + u16 y; + s8 z; + + target_present =3D + FIELD_GET(AX_U41_PRESENT_MASK, get_unaligned_le16(&report[0])); + + for (i =3D 0; i < U41_MAX_TARGETS; i++) { + active =3D !!((target_present >> i) & 1); + + offset =3D U41_X_Y_OFFSET + (i * U41_COORD_SIZE); + x =3D get_unaligned_le16(&report[offset]); + y =3D get_unaligned_le16(&report[offset + 2]); + z =3D report[U41_Z_OFFSET + i]; + + if (!active) + state =3D Target_State_Not_Present; + else if (z >=3D 0) + state =3D Target_State_Touching; + else if ((z > U41_PROX_LEVEL) && (z < 0)) + state =3D Target_State_Hover; + else if (z =3D=3D U41_PROX_LEVEL) + state =3D Target_State_Prox; + else + state =3D Target_State_Not_Present; + + dev_dbg(ax->dev, "Target %d: x=3D%u y=3D%u z=3D%d present=3D%d\n", i, x, + y, z, active); + + switch (state) { + case Target_State_Not_Present: + case Target_State_Prox: + + input_mt_slot(ax->input, i); + input_mt_report_slot_inactive(ax->input); + break; + + case Target_State_Hover: + case Target_State_Touching: + + input_mt_slot(ax->input, i); + input_report_abs(ax->input, ABS_MT_TRACKING_ID, i); + input_report_abs(ax->input, ABS_MT_POSITION_X, x); + input_report_abs(ax->input, ABS_MT_POSITION_Y, y); + + if (state =3D=3D Target_State_Touching) { + input_report_abs(ax->input, ABS_MT_DISTANCE, 0); + input_report_abs(ax->input, ABS_MT_PRESSURE, z); + } else { /* Hover */ + input_report_abs(ax->input, ABS_MT_DISTANCE, -z); + input_report_abs(ax->input, ABS_MT_PRESSURE, 0); + } + break; + + default: + break; + } + } + + input_mt_sync_frame(ax->input); + input_sync(ax->input); + + return 0; +} + +static int axiom_process_report(struct axiom *ax, u8 *report) +{ + int err; + struct u34_report_header hdr; + u16 crc_calc; + u16 crc_report; + u8 len; + u16 hdr_buf =3D get_unaligned_le16(&report[0]); + + dev_dbg(ax->dev, "Payload Data %*ph\n", ax->max_report_len, report); + + hdr.report_length =3D FIELD_GET(AX_U34_LEN_MASK, hdr_buf); + hdr.overflow =3D !!(hdr_buf & AX_U34_OVERFLOW); + hdr.report_usage =3D FIELD_GET(AX_U34_USAGE_MASK, hdr_buf); + + len =3D hdr.report_length << 1; + if (hdr.report_length =3D=3D 0) { + dev_err(ax->dev, "Zero length report discarded.\n"); + return -EIO; + } + + // Length is 16 bit words and remove the size of the CRC16 itself + crc_report =3D (report[len - 1] << 8) | (report[len - 2]); + crc_calc =3D crc16(0, report, (len - 2)); + + if (crc_calc !=3D crc_report) { + dev_err(ax->dev, + "CRC mismatch! Expected: %04X, Calculated CRC: %04X. Report discarded.\= n", + crc_report, crc_calc); + return -EIO; + } + + switch (hdr.report_usage) { + case AX_2DCTS_REPORT_ID: + err =3D axiom_process_u41_report(ax, + &report[AX_U34_PAYLOAD_BUFFER]); + break; + + default: + break; + } + + return err; +} + +static void axiom_poll(struct input_dev *input_dev) +{ + struct axiom *ax =3D input_get_drvdata(input_dev); + int err; + + /* Read touch reports from u34 */ + err =3D ax->bus_ops->read(ax->dev, ax->u34_address, ax->max_report_len, + ax->read_buf); + if (err) + return; + + err =3D axiom_process_report(ax, ax->read_buf); + if (err) + dev_err(ax->dev, "Failed to process report: %d\n", err); +} + +static irqreturn_t axiom_irq(int irq, void *handle) +{ + struct axiom *ax =3D handle; + int err; + + /* Read touch reports from u34 */ + err =3D ax->bus_ops->read(ax->dev, ax->u34_address, ax->max_report_len, + ax->read_buf); + if (err) + goto out; + + err =3D axiom_process_report(ax, ax->read_buf); + if (err) + dev_err(ax->dev, "Failed to process report: %d\n", err); + +out: + return IRQ_HANDLED; +} + +struct axiom *axiom_probe(const struct axiom_bus_ops *bus_ops, + struct device *dev, int irq) +{ + struct axiom *ax; + struct input_dev *input_dev; + int err; + bool poll_enable =3D false; + u8 poll_period =3D 0; + + ax =3D devm_kzalloc(dev, sizeof(*ax), GFP_KERNEL); + if (!ax) + return ERR_PTR(-ENOMEM); + + input_dev =3D devm_input_allocate_device(dev); + if (!input_dev) { + pr_err("ERROR: aXiom-core: Failed to allocate memory for input device!\n= "); + return ERR_PTR(-ENOMEM); + } + + poll_enable =3D device_property_read_bool(dev, "axiom,poll-enable"); + + device_property_read_u8(dev, "axiom,poll-period", &poll_period); + if (!poll_period) + poll_period =3D AX_POLLING_PERIOD_MS; + + ax->dev =3D dev; + ax->input =3D input_dev; + ax->bus_ops =3D bus_ops; + ax->irq =3D irq; + + dev_info(dev, "aXiom Probe\n"); + if (poll_enable) + dev_info(dev, "Polling Period : %u\n", poll_period); + else + dev_info(dev, "Device IRQ : %u\n", ax->irq); + + axiom_set_capabilities(input_dev); + + err =3D axiom_init_dev_info(ax); + if (err) { + dev_err(ax->dev, "Failed to read device info, err: %d\n", err); + return ERR_PTR(err); + } + + if (poll_enable) { + err =3D input_setup_polling(input_dev, axiom_poll); + if (err) { + dev_err(ax->dev, "could not set up polling mode, %d\n", + err); + return ERR_PTR(err); + } + + input_set_poll_interval(input_dev, poll_period); + } else { + err =3D devm_request_threaded_irq(ax->dev, ax->irq, NULL, + axiom_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "axiom_irq", ax); + if (err) + return ERR_PTR(err); + } + + err =3D input_register_device(input_dev); + if (err) { + dev_err(ax->dev, "Failed to register input device: %d\n", err); + return ERR_PTR(err); + } + + input_set_drvdata(input_dev, ax); + + return ax; +} +EXPORT_SYMBOL_GPL(axiom_probe); + +MODULE_AUTHOR("TouchNetix "); +MODULE_DESCRIPTION("aXiom touchscreen core logic"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("axiom"); +MODULE_VERSION("1.0.0"); diff --git a/drivers/input/touchscreen/axiom_core.h b/drivers/input/touchsc= reen/axiom_core.h new file mode 100644 index 000000000000..ca77f9038cb1 --- /dev/null +++ b/drivers/input/touchscreen/axiom_core.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2020-2026 TouchNetix Ltd. + * + * Author(s): Mark Satterthwaite + * Pedro Torruella + * Bart Prescott + * Hannah Rossiter + * Andrew Thomas + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef __AXIOM_CORE_H +#define __AXIOM_CORE_H + +#include + +#define AX_POLLING_PERIOD_MS (10) + +#define AXIOM_USE_TOUCHSCREEN_INTERFACE // registers the axiom device as a= touch screen instead of as a mouse pointer +#define U46_ENABLE_RAW_FORCE_DATA // enables the raw data for up to 4 forc= e channels to be sent to the input subsystem + +#define AXIOM_PAGE_SIZE (256) +// u31 has 2 pages for usage table entries. (2 * PAGE_SIZE) / U31_BYTES_PE= R_USAGE =3D 85 +#define AXIOM_MAX_READ_SIZE (2 * AXIOM_PAGE_SIZE) +#define SIZE_U31_DEVICE_INFO (12) +#define SIZE_U31_USAGE_ENTRY (6) +#define U31_MAX_USAGES (85U) +#define U41_MAX_TARGETS (10U) +#define U41_PROX_LEVEL (-128) +#define AXIOM_HOLDOFF_DELAY_US (40) + +enum ax_comms_op_e { AX_WR_OP =3D 0, AX_RD_OP =3D 1 }; + +enum report_ids_e { + AX_2DCTS_REPORT_ID =3D 0x41, +}; + +enum axiom_mode_e { + AX_RUNTIME_STATE =3D 0, + AX_BOOTLOADER_STATE =3D 1, +}; + +enum usage_type_e { + UNKNOWN =3D 0, + OTHER =3D 1, + REPORT =3D 2, + REGISTER =3D 3, + REGISTER_READ_ONLY_ =3D 4, + CDU =3D 5, + CDU_READ_ONLY_ =3D 6, +}; + +struct axiom_device_info { + u16 device_id; + u8 mode; + u8 runtime_fw_rev_minor; + u8 runtime_fw_rev_major; + u8 device_build_variant; + u8 runtime_fw_status; + u8 tcp_revision; + u8 bootloader_fw_rev_minor; + u8 bootloader_fw_rev_major; + u8 jedec_id; + u8 num_usages; + u8 silicon_revision; + u8 runtime_fw_rev_patch; +}; + +struct u31_usage_entry { + u8 usage_num; + u8 start_page; + u8 num_pages; + u8 max_offset; + u8 offset_type; + u8 uifrevision; + u8 usage_type; +}; + +struct axiom_cmd_header { + u16 target_address; + u16 length : 15; + u16 rd_wr : 1; +}; + +struct axiom_bus_ops { + u16 bustype; + int (*write)(struct device *dev, u16 addr, u16 length, void *values); + int (*read)(struct device *dev, u16 addr, u16 length, void *values); +}; + +enum u41_target_state_e { + Target_State_Not_Present =3D 0, + Target_State_Prox =3D 1, + Target_State_Hover =3D 2, + Target_State_Touching =3D 3, +}; + +struct axiom { + struct device *dev; + int irq; + struct input_dev *input; + const struct axiom_bus_ops *bus_ops; + struct axiom_device_info dev_info; + struct u31_usage_entry usage_table[U31_MAX_USAGES]; + u16 max_report_len; + u16 u34_address; + + u8 read_buf[AXIOM_MAX_READ_SIZE]; +}; + +struct u34_report_header { + u8 report_length; + u8 overflow; + u8 report_usage; +}; + +struct axiom *axiom_probe(const struct axiom_bus_ops *bus_ops, + struct device *dev, int irq); + +#endif /* __AXIOM_CORE_H */ diff --git a/drivers/input/touchscreen/axiom_i2c.c b/drivers/input/touchscr= een/axiom_i2c.c new file mode 100644 index 000000000000..66071cc0f7b3 --- /dev/null +++ b/drivers/input/touchscreen/axiom_i2c.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2020-2026 TouchNetix Ltd. + * + * Author(s): Bart Prescott + * Pedro Torruella + * Mark Satterthwaite + * Hannah Rossiter + * Andrew Thomas + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +// #define DEBUG // Enable debug messages + +#include +#include +#include +#include +#include +#include "axiom_core.h" + +static int axiom_i2c_read_block_data(struct device *dev, u16 addr, u16 len= gth, + void *values) +{ + int error; + struct i2c_client *client =3D to_i2c_client(dev); + struct axiom_cmd_header cmd_header =3D { .target_address =3D addr, + .length =3D length, + .rd_wr =3D AX_RD_OP }; + + struct i2c_msg msgs[] =3D { + { + .addr =3D client->addr, + .flags =3D 0, + .len =3D sizeof(cmd_header), + .buf =3D (u8 *)&cmd_header, + }, + { + .addr =3D client->addr, + .flags =3D I2C_M_RD, + .len =3D length, + .buf =3D values, + }, + }; + + error =3D i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (error < 0) { + dev_err(dev, "I2C transfer error: %d\n", error); + return error; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return error !=3D ARRAY_SIZE(msgs) ? -EIO : 0; +} + +static int axiom_i2c_write_block_data(struct device *dev, u16 addr, u16 le= ngth, + void *values) +{ + int error; + struct i2c_client *client =3D to_i2c_client(dev); + struct axiom_cmd_header cmd_header =3D { .target_address =3D addr, + .length =3D length, + .rd_wr =3D AX_WR_OP }; + + struct i2c_msg msgs[] =3D { + { + .addr =3D client->addr, + .flags =3D 0, + .len =3D sizeof(cmd_header), + .buf =3D (u8 *)&cmd_header, + }, + { + .addr =3D client->addr, + .flags =3D 0, + .len =3D length, + .buf =3D values, + }, + }; + + error =3D i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (error < 0) { + dev_err(dev, "I2C transfer error: %d\n", error); + return error; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return error !=3D ARRAY_SIZE(msgs) ? -EIO : 0; +} + +static const struct axiom_bus_ops axiom_i2c_bus_ops =3D { + .bustype =3D BUS_I2C, + .write =3D axiom_i2c_write_block_data, + .read =3D axiom_i2c_read_block_data, +}; + +static int axiom_i2c_probe(struct i2c_client *client) +{ + struct axiom *axiom; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "I2C functionality not Supported\n"); + return -EIO; + } + + axiom =3D axiom_probe(&axiom_i2c_bus_ops, &client->dev, client->irq); + if (IS_ERR(axiom)) + return dev_err_probe(&client->dev, PTR_ERR(axiom), + "failed to register input device\n"); + + return 0; +} + +static const struct i2c_device_id axiom_i2c_id_table[] =3D { + { "axiom-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, axiom_i2c_id_table); + +static const struct of_device_id axiom_i2c_dt_ids[] =3D { + { + .compatible =3D "tnx,axiom-i2c", + .data =3D "axiom", + }, + {} +}; +MODULE_DEVICE_TABLE(of, axiom_i2c_dt_ids); + +static struct i2c_driver axiom_i2c_driver =3D { + .driver =3D { + .name =3D "axiom_i2c", + .of_match_table =3D of_match_ptr(axiom_i2c_dt_ids), + }, + .id_table =3D axiom_i2c_id_table, + .probe =3D axiom_i2c_probe, +}; + +module_i2c_driver(axiom_i2c_driver); + +MODULE_AUTHOR("TouchNetix "); +MODULE_DESCRIPTION("aXiom touchscreen I2C bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("axiom"); +MODULE_VERSION("1.0.0"); diff --git a/drivers/input/touchscreen/axiom_spi.c b/drivers/input/touchscr= een/axiom_spi.c new file mode 100644 index 000000000000..a67ad3645689 --- /dev/null +++ b/drivers/input/touchscreen/axiom_spi.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TouchNetix aXiom Touchscreen Driver + * + * Copyright (C) 2018-2023 TouchNetix Ltd. + * + * Author(s): Mark Satterthwaite + * Bart Prescott + * Hannah Rossiter + * Andrew Thomas + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +// #define DEBUG // Enable debug messages + +#include +#include +#include +#include +#include +#include +#include "axiom_core.h" + +#define SPI_PADDING_LEN 32 + +static int axiom_spi_transfer(struct device *dev, enum ax_comms_op_e op, + u16 addr, u16 length, void *values) +{ + int ret; + struct spi_device *spi =3D to_spi_device(dev); + struct spi_transfer xfr_header; + struct spi_transfer xfr_padding; + struct spi_transfer xfr_payload; + struct spi_message msg; + struct axiom_cmd_header cmd_header =3D { .target_address =3D addr, + .length =3D length, + .rd_wr =3D op }; + u8 pad_buf[SPI_PADDING_LEN] =3D { 0 }; + + memset(&xfr_header, 0, sizeof(xfr_header)); + memset(&xfr_padding, 0, sizeof(xfr_padding)); + memset(&xfr_payload, 0, sizeof(xfr_payload)); + + /* Setup the SPI transfer operations */ + xfr_header.tx_buf =3D &cmd_header; + xfr_header.len =3D sizeof(cmd_header); + + xfr_padding.tx_buf =3D pad_buf; + xfr_padding.len =3D sizeof(pad_buf); + + switch (op) { + case AX_WR_OP: + xfr_payload.tx_buf =3D values; + break; + case AX_RD_OP: + xfr_payload.rx_buf =3D values; + break; + default: + dev_err(dev, "%s: invalid operation: %d\n", __func__, op); + return -EINVAL; + } + xfr_payload.len =3D length; + + spi_message_init(&msg); + spi_message_add_tail(&xfr_header, &msg); + spi_message_add_tail(&xfr_padding, &msg); + spi_message_add_tail(&xfr_payload, &msg); + + ret =3D spi_sync(spi, &msg); + if (ret < 0) { + dev_err(&spi->dev, "Failed to SPI transfer, error: %d\n", ret); + return ret; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return 0; +} + +static int axiom_spi_read_block_data(struct device *dev, u16 addr, u16 len= gth, + void *values) +{ + return axiom_spi_transfer(dev, AX_RD_OP, addr, length, values); +} + +static int axiom_spi_write_block_data(struct device *dev, u16 addr, u16 le= ngth, + void *values) +{ + return axiom_spi_transfer(dev, AX_WR_OP, addr, length, values); +} + +static const struct axiom_bus_ops axiom_spi_bus_ops =3D { + .bustype =3D BUS_SPI, + .write =3D axiom_spi_write_block_data, + .read =3D axiom_spi_read_block_data, +}; + +static int axiom_spi_probe(struct spi_device *spi) +{ + struct axiom *axiom; + int error; + + /* Set up SPI */ + spi->bits_per_word =3D 8; + spi->mode =3D SPI_MODE_0; + spi->max_speed_hz =3D 4000000; + + if (spi->irq =3D=3D 0) + dev_err(&spi->dev, "No IRQ specified!\n"); + + error =3D spi_setup(spi); + if (error < 0) { + dev_err(&spi->dev, "%s: SPI setup error %d\n", __func__, error); + return error; + } + axiom =3D axiom_probe(&axiom_spi_bus_ops, &spi->dev, spi->irq); + if (IS_ERR(axiom)) + return dev_err_probe(&spi->dev, PTR_ERR(axiom), + "failed to register input device\n"); + + return 0; +} + +static const struct spi_device_id axiom_spi_id_table[] =3D { + { "axiom-spi" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, axiom_spi_id_table); + +static const struct of_device_id axiom_spi_dt_ids[] =3D { + { + .compatible =3D "tnx,axiom-spi", + .data =3D "axiom", + }, + {} +}; +MODULE_DEVICE_TABLE(of, axiom_spi_dt_ids); + +static struct spi_driver axiom_spi_driver =3D { + .id_table =3D axiom_spi_id_table, + .driver =3D { + .name =3D "axiom_spi", + .of_match_table =3D of_match_ptr(axiom_spi_dt_ids), + }, + .probe =3D axiom_spi_probe, +}; + +module_spi_driver(axiom_spi_driver); + +MODULE_AUTHOR("TouchNetix "); +MODULE_DESCRIPTION("aXiom touchscreen SPI bus driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("axiom"); +MODULE_VERSION("1.0.0"); --=20 2.43.0 From nobody Sun Feb 8 14:22:01 2026 Received: from eu-smtp-delivery-101.mimecast.com (eu-smtp-delivery-101.mimecast.com [185.58.86.101]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 39B1D1DE4DC for ; Thu, 22 Jan 2026 14:42:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.58.86.101 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769092978; cv=none; b=fWqCGSwWGQSRvOZO6CLXgbbWWJvcERcDLsovXGBKcQEvGz9izVYjVYQgMVJSrlGb2faDuxl8Dw7WDKLSbHxxUYnK8hNwPygIBWEJ4UbUn30i4Efdqo/PEFqYf9Lqakg0WZ3+5DsNaUk2qy0kNuxdg7eWk6TcO9XFFPNXgOm7aRU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769092978; c=relaxed/simple; bh=Cw0skZtBCGqWfjheUXINhljgkQzJdlf8/iK6PXySs60=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QHQz2b7IhEvXfhr8GyDIR6IaAuT/OlCjr3tMHTzeXYljlA3l7vUlfFIBpioDwihVLQsokTeaqWILhZXRd3MSc3SuGhhMhEMUIlXISLUfEzHmFvUzVEeowU90ZBdeF6vA5gLAp4uVIKoDn+7kkwoiULTvstwQQ4OFnb/U8YxQybQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=touchnetix.com; spf=pass smtp.mailfrom=touchnetix.com; arc=none smtp.client-ip=185.58.86.101 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=touchnetix.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=touchnetix.com Received: from CWXP265CU009.outbound.protection.outlook.com (mail-ukwestazon11021139.outbound.protection.outlook.com [52.101.100.139]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id uk-mta-125-gL_8azeVNS60PX5GeFm7jg-1; Thu, 22 Jan 2026 14:42:51 +0000 X-MC-Unique: gL_8azeVNS60PX5GeFm7jg-1 X-Mimecast-MFC-AGG-ID: gL_8azeVNS60PX5GeFm7jg_1769092971 Received: from LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:e9::9) by LO6P123MB6721.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:2d9::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.11; Thu, 22 Jan 2026 14:42:49 +0000 Received: from LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM ([fe80::4a94:a629:f86f:40d1]) by LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM ([fe80::4a94:a629:f86f:40d1%4]) with mapi id 15.20.9542.009; Thu, 22 Jan 2026 14:42:49 +0000 From: AThomas63 To: dmitry.torokhov@gmail.com CC: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, mark.satterthwaite@touchnetix.com, andrew.thomas@touchnetix.com, m.felsch@pengutronix.de, kamel.bouhara@bootlin.com Subject: [PATCH v1] dt-bindings: input: Add TouchNetix aXiom touchscreen driver Date: Thu, 22 Jan 2026 14:40:52 +0000 Message-ID: <20260122144052.358956-1-andrew.thomas@touchnetix.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260122124819.273188-1-andrew.thomas@touchnetix.com> References: <20260122124819.273188-1-andrew.thomas@touchnetix.com> X-ClientProxiedBy: LO6P265CA0008.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:339::18) To LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:e9::9) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: LOYP123MB2701:EE_|LO6P123MB6721:EE_ X-MS-Office365-Filtering-Correlation-Id: dfc73aa3-baa0-417f-7172-08de59c483d7 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|366016|1800799024|52116014|376014|38350700014 X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?//marZ7Xl37GZ36Cv6MR0gcu1/RM5tF1Hzcijyb3lfAvGEekYrg0V6IHFvIa?= =?us-ascii?Q?9fhIDnrmWo7MquMVPbZxp49ZihFXzpPsBTF28ChqVVGQ10RcMMQNpUCi/coV?= =?us-ascii?Q?5FlLOXpdPUiMZGUw2aJOHMNTBB1kIoW+Ltj7hffNzW7tt+P1NQw8I10Hk77g?= =?us-ascii?Q?kOT7xTiS1kecPG9KD62SUfojx7Xiu1ETnXzcaB0nVrrWQoS49dx/YWp9mBBA?= =?us-ascii?Q?oriX4NSwBqvDDakDgjMt4lYltSUIKV3ru7mRN/hRtTUbg9bCYcNbMfra8bCB?= =?us-ascii?Q?AzdtX2w4/WcFqYij0sASB4NyPo4AOtF/Cly7nqZBoMfXu8UXRAXXTnO0yF7M?= =?us-ascii?Q?vF8/sTwirtFJ4+nw5WMtDIYklWVXar9200RqCLdyfAvKGOgoASa6CGKmE8FY?= =?us-ascii?Q?h+AV3kCd/H9YSfbT4W42zSOgVa+r+mguHjHA/uA7Yj76PpSr9wEbPZ27WF9A?= =?us-ascii?Q?Mru5ozlhdTig4B2v+O2GfCmHjT0keUZwkul1a5Tqbui5o05hDU1lsGA+kc2c?= =?us-ascii?Q?mv1jMoN+4XL+bkq/vvAFiUPyTSMiaGfpoeE5qOj7+N6dtaES77/Kq4KVXBgx?= =?us-ascii?Q?fcpJs3ypli8wZkzoMBvScc/P5/aqyIAfEAMg8wWJ4sBGFUKGLa4JpsLD+w+g?= =?us-ascii?Q?OAQfijKXOvl+zUkbsMdpIgJmgBKD5JjpdCrq8eb6dBAwjzaRsfATnTjezOjW?= =?us-ascii?Q?yNsKkRdBRQfEZUhALLZ9HknxcUYHnWgnVSVfxmpJsLX8uCJnLG9wUhclOLz4?= =?us-ascii?Q?K+Nk63DuUCFll24lgVFSkCSRYBzkgTmnE5203icrivRTx8T2rGrRMnhKvOmf?= =?us-ascii?Q?PL2lGFhYnNbQ7MUFqdeXNlxMdp24+5LHfIanY8MO+B3iwEED3m78Go+G3AxB?= =?us-ascii?Q?XwNjPOHhhMBkvvd6G0Vs3p3yq7IvY0gnpmexs6ETS4orAwf3kIc/6sEeihiQ?= =?us-ascii?Q?QZq5Rtr+CUC83wiAIuqyVBhfyxWQl84x2m7sjKqngG1uV/1I9V3a61HkhjAN?= =?us-ascii?Q?DKqQt0px0bqSf3zHnGdN4P2Df8QKcec/dr8fmOovD621PjNwm8F5Nski4xpA?= =?us-ascii?Q?r08VcqPNDBXiNe64wsinK7/KwLGvVA6hYDHAu80fo1angruVlDR/lM8YZEH6?= =?us-ascii?Q?+AYqtIqZU6gua7CIVenBb6Gljo5sWEmI01PP8kl0/I9LN2ZdHpGMf3FCjqfk?= =?us-ascii?Q?WxEOu78C29ZQaNK0KWiEsSZV6oPdlcpos78+f//0t8SJ7+0R65wbqXev+Nf1?= =?us-ascii?Q?PqwHU1haTOZNCR7RMTaF9hixz61QLTEwxnab1IPx4Vn9IRv6RKODAdjNKRSp?= =?us-ascii?Q?wbDJPk/bdfioFgzGzuFLGLiYUiSMG+WFxCgecIIA03ie3EUnctVseDEvMuTR?= =?us-ascii?Q?ktEGq1twpaG5Rsh4oqUnANN9QcrGKJaKrPP5wy2PU/a5jhNgWHRj/2MEr1R1?= =?us-ascii?Q?SqlKmUUb/PIPsBvREu0mVQcAC8dc1+dLe5Dtxz4nQ24oQmhhdcd2nFs5Ulwq?= =?us-ascii?Q?T9OlhDzsd7at/ti4U8CHstLGK1FIG5Jc8Vk/1Z5N7UAZcUndn4mq/z/VKmsx?= =?us-ascii?Q?xO1W8ByTBw9x2cPE8+zTgU+4Z/TlFIveUXhuzQzO?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM;PTR:;CAT:NONE;SFS:(13230040)(366016)(1800799024)(52116014)(376014)(38350700014);DIR:OUT;SFP:1102 X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Ao/EeRtgtZNrfoQ7o9Ary38zbkKMtZ5O2x7+A+wyOcGyCTe/l4XnWV0Udzgn?= =?us-ascii?Q?JAGh7UOgEsJsxg+Ky44TkMxYopjd2b4+lBVVe6UMv26F1xTdgyujgz4QiUsu?= =?us-ascii?Q?JTEhBX0uva3t8ZVnyZmr4ZrwPHRGMfV8Dn/sKTSc/oRP9c1AYqQmVUyJrqMa?= =?us-ascii?Q?hPjKUzmGeMw7BCr0DgqbW9ZZOhpSb80S/f4pc6RE2fAdCiY0vUIEtSIO+50v?= =?us-ascii?Q?g9tmmrmVrcsFyKmXpTryP6rSfTHahNdhX3Aa2ck6q/nd0GJqeL8fCeKOq91i?= =?us-ascii?Q?Bn5O1n6QEK4UqI0I+MxteTopuyVSRe9Fjk7l86NVeI9SacjY60DIW9+WowaK?= =?us-ascii?Q?/EvSRe3YsK0x1pImOYA9JAKpFZCJXuQT/r28plzMpDmb4vn4F7vxsYtBWck/?= =?us-ascii?Q?Nyu7n9qMsygo7hVGwwnVTDEXm+S1B2COGqHyTl/rqWRmmXFW+2llRgDyV5Vp?= =?us-ascii?Q?LJ7Y6T6s6wF1+A1fRm68ljii+XIFKE2tCy6NrzGVnqOulanpDWHJP1WLrknf?= =?us-ascii?Q?60Pu5DuFMsQrXv3CP6SReWKR/v/xp9eBp6drvWZUhBYBbfL6LRhk+Ck5MsZV?= =?us-ascii?Q?VQeb3c6AzdoAG1lEvEnqWIrlMgQSlWM5OOryc3CJqcaXVEQEIuzNuohNI7Kk?= =?us-ascii?Q?2ncVrJlUyd/DWJYO6ju56FUvEwyUlFYL8Z31kesu11W/s+feQ0hBptuXj4Cf?= =?us-ascii?Q?W+KID0I854EHKUK5dd49NExOgJF2JpZuTEW1OHygXMods8jvW+HimIVS3g7U?= =?us-ascii?Q?JFMHssErycTsEYqo28lkRgrODUXo/CYs9uqfBJ7Ap4abspFOq89PdHaM7KU8?= =?us-ascii?Q?7uOxWHMwc4jLGNBRKlWYUqcZFOIXHvmI4dt5NCwyNzwUMimt+Dlqd2Obugke?= =?us-ascii?Q?9JjSGRmrQTIztQjMLiBdSQpPSdOo4sGIc8VOHcVzu2aoODgrrKH8xnVQaOVL?= =?us-ascii?Q?ASDcOnDHdasZnBXhpNfgFm24gKsNPpyO3FFU8oex/DRzSM5320FbOoFgvf63?= =?us-ascii?Q?Yu3TCWBqcSS110G99WyFffSvLLyYpRg1BQ7s80ZEO6m5q1EgM8wRYuif2R81?= =?us-ascii?Q?ooWFKjq3o5bsoErpDy6On/4mbDZVtKSEKBFEZ8DKrFnxwqH1XYlTIlNqNcbs?= =?us-ascii?Q?gy3vA062Jh8epcgChPUkwOaSv0JFGXVLn5CgycCSWCq51mH/nkpB2THphE4c?= =?us-ascii?Q?Y7bhkwIL3sh/OZGT3yUYQqqHl4aJkovkUnBjSKAAOZMiYjquRTkN+j1YpTGn?= =?us-ascii?Q?NFqZ382eBlDYFbUBxaMJB8HXyaqLzz3Zl6CUJgCDuo9tZC/ZPD5bDb3MitTZ?= =?us-ascii?Q?oyPdz+DdyyHsLyiuI/juD4ZIFYG6dW19pvdAW63Bk6oeLgk8xOA11wE+3x+x?= =?us-ascii?Q?k41v/kRi86kyiI/kc19yblqopWUu7cwag/8ilh5ZXmottQ+SPkLyNt6oWuYg?= =?us-ascii?Q?glSWs2kk2yd8/+fdJF7hzKncjYGNX+zsy62fCawU9m/FZeZSPg+wrA7Il8rZ?= =?us-ascii?Q?qVGHiNFMfRFzdoumEcvpyuopLFDRe+/KXn4SN4Rm0B5sM+a0fsf2/4sYbK/I?= =?us-ascii?Q?jsOG+Jeabx3uFpLpCo0UEBLk0AWI0pe16Ucg90Qx0SurzSnSqX2S9O+GQTnz?= =?us-ascii?Q?YK8cr3Hf3PHijkWDtgqEcDLM9ZyTKhHU21byTc1WXW7sjb0elPVok8VCZPiG?= =?us-ascii?Q?1SY1M6YB7L65m5SS/JgoLnWEB4nfCBwfMYsKgV93r9f1TTebSgCEKlsORxof?= =?us-ascii?Q?l1/unW1QaVqUg2PiPjVF/FAezFU+ZFU=3D?= X-OriginatorOrg: touchnetix.com X-MS-Exchange-CrossTenant-Network-Message-Id: dfc73aa3-baa0-417f-7172-08de59c483d7 X-MS-Exchange-CrossTenant-AuthSource: LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Jan 2026 14:42:49.4445 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 120474da-7cc3-44b9-aff9-438a33341070 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 2kN/0znctceNBbol91EHrTBSHNBXfyQDupqufud4BLbtRlM0OLZvKl6uZuP70JnveFUcFAtMLEI2ku4JVCqD2avv9eUOcCAGfAuCMFgfSm0= X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO6P123MB6721 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: INruOYkXzEpLqRaij2e2RbaWml8zS6dZJU79why1oAk_1769092971 X-Mimecast-Originator: touchnetix.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add extra changes referenced in the previous patch: - Add device tree documentation for axiom giving examples for SPI and I2C. - Add tnx vendor prefix. --- .../bindings/input/touchscreen/tnx,axiom.yaml | 90 +++++++++++++++++++ .../devicetree/bindings/vendor-prefixes.yaml | 2 + 2 files changed, 92 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/tnx= ,axiom.yaml diff --git a/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.= yaml b/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml new file mode 100644 index 000000000000..dc2ea62999b8 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml @@ -0,0 +1,90 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/tnx,axiom.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TouchNetix aXiom Touchscreen Controller + +maintainers: + - Andrew Thomas + +description: | + The TouchNetix aXiom series are high-performance touchscreen controllers + supporting various interface methods including I2C and SPI. + +properties: + compatible: + enum: + - tnx,axiom-i2c + - tnx,axiom-spi + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + axiom,poll-enable: + type: boolean + description: Enable aXiom polling mode instead of interrupt-driven=20 + reporting. + + axiom,poll-period: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 10 + description: Set the polling period in milliseconds. + + # Required for SPI + spi-max-frequency: true + + # Common touchscreen properties + touchscreen-size-x: true + touchscreen-size-y: true + touchscreen-inverted-x: true + touchscreen-inverted-y: true + touchscreen-swapped-x-y: true + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: touchscreen.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + touchscreen@66 { + compatible =3D "touchnetix,axiom-i2c"; + reg =3D <0x66>; + interrupt-parent =3D <&gpio>; + interrupts =3D <24 IRQ_TYPE_LEVEL_LOW>; + axiom,poll-enable; + axiom,poll-period =3D <15>; + }; + }; + + - | + #include + + spi { + #address-cells =3D <1>; + #size-cells =3D <0>; + + touchscreen@0 { + compatible =3D "touchnetix,axiom-spi"; + reg =3D <0>; + spi-max-frequency =3D <4000000>; + interrupt-parent =3D <&gpio>; + interrupts =3D <24 IRQ_TYPE_LEVEL_LOW>; + }; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Docum= entation/devicetree/bindings/vendor-prefixes.yaml index f1d1882009ba..dadfc7036ed7 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -1636,6 +1636,8 @@ patternProperties: description: Trusted Logic Mobility "^tmt,.*": description: Tecon Microprocessor Technologies, LLC. + "^tnx,.*": + description: TouchNetix "^topeet,.*": description: Topeet "^topic,.*": --=20 2.43.0