From nobody Mon Jan 26 22:57:56 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 3201C28C854 for ; Mon, 26 Jan 2026 16:39:06 +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=1769445548; cv=none; b=brIMAjYJmIOn/lqASe4XCIxA6FFE6cYKubCixTpQH0S9ucyfYZKfBVRp9HNHMfqZGNyIJGIaX15ZHWCaslQs4dO+DcZSDKokjBJM2021nQsBfKAxIjK01Q0AIfns6OHLm0sL71n33XBYbjkN7/ytzyZoDr2CbWpHDSqYudJfyY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769445548; c=relaxed/simple; bh=qU9hjkq02RMfBGJ2ZqhX7fSjNIf1NBEX8j93ChbZpvE=; h=From:Date:Subject:Message-Id:References:In-Reply-To:To:Cc: MIME-Version:Content-Type; b=KOmkoAPFQN94QWv5eBFI/Q9gdDnmgPLKQURxKnL6+nj7dJCnKp93Jxt8C67uohwYGNSOG6hluBLgxO3gyTAXteg+1IcWb8wVuzAFtvei3RoV7OaP8Maxs6dsKF8jWz+EHj4w/DMpVj3B0OBspu3Gr7l1UzTAyGQMsI2L9cOhMzA= 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 CWXP265CU010.outbound.protection.outlook.com (mail-ukwestazon11022082.outbound.protection.outlook.com [52.101.101.82]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id uk-mta-187-Xl0D4wSxOoSLBKuHw1ZDCw-2; Mon, 26 Jan 2026 16:38:58 +0000 X-MC-Unique: Xl0D4wSxOoSLBKuHw1ZDCw-2 X-Mimecast-MFC-AGG-ID: Xl0D4wSxOoSLBKuHw1ZDCw_1769445537 Received: from LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:e9::9) by LO2P123MB3824.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:12d::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.12; Mon, 26 Jan 2026 16:38:54 +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.010; Mon, 26 Jan 2026 16:38:54 +0000 From: Andrew Thomas Date: Mon, 26 Jan 2026 16:38:23 +0000 Subject: [PATCH 1/2] dt-bindings: input: touchscreen: add TouchNetix aXiom device tree Message-Id: <20260126-axiom-driver-submission3-v1-1-d462c4a608e3@touchnetix.com> References: <20260126-axiom-driver-submission3-v1-0-d462c4a608e3@touchnetix.com> In-Reply-To: <20260126-axiom-driver-submission3-v1-0-d462c4a608e3@touchnetix.com> To: Dmitry Torokhov , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Henrik Rydberg Cc: linux-input@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Andrew Thomas , Marco Felsch X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769445534; l=2763; i=andrew.thomas@touchnetix.com; s=20260126; h=from:subject:message-id; bh=UJ2CZxwm3skLzsg4d1bbLkCekiBEDSRN6CMUdDhOWyU=; b=RRmsHjtWMk+oJrEAw0oljoBlOWzbkAQK2Pu66f4LjtVVReFJ1pFaQflg2T0K0MGsCCtlhseJL bsMUnUA13Q1CLvPBvw7WS4IXoiB2YoM8MRGu08DkXlCFxQJ7IsUydgN X-Developer-Key: i=andrew.thomas@touchnetix.com; a=ed25519; pk=GtS7O+T7kMl4PPu344KeKG2xlsaHEzDUFLtOqb5JPPg= X-ClientProxiedBy: LO6P123CA0059.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:310::17) 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_|LO2P123MB3824:EE_ X-MS-Office365-Filtering-Correlation-Id: 6841690b-d196-4e9a-48ca-08de5cf964b6 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|52116014|366016|38350700014 X-Microsoft-Antispam-Message-Info: =?utf-8?B?VVdJZDNqUEFjT3VTR3VTUS95dnN5RHFUY0gxeXdUYmtOZnB5Mko2em9uak0r?= =?utf-8?B?YU5aaHVJVXlRZzhaYUlFcHhuUUlscHlKdmFQS2NmTEE1QjZpS3V1eFJVU0hu?= =?utf-8?B?REd5a3BUMGNZaW1pemZKdG16L1BUbXZIb2ppNjgxYWtibk8xWGJmMy9ZVmNn?= =?utf-8?B?RzUxOSttZTZVUDdKQnVMVFNzbUdzZzBjQkVRSUVIZHZ4MjE3YlV5SVlQQ0Vz?= =?utf-8?B?TzR6WmZCc0E5SkMyOUZYbDBSY1owSW5jNTl1MEhkdUh4WGxGUjljNW1yQjRa?= =?utf-8?B?TjdTN0t0RnpQdTZldXdGVTZEaVBDNHJWTGZDZ2twUHhCdlByTVUxaG5QTm9E?= =?utf-8?B?MWlNRFhCa0V0MEp4a0F5b3BQaVc2dE52TU90NVF2TzNxNkdwd3FlVGswSXp4?= =?utf-8?B?d3I1ekl2YTJNWnRZTkdCKzZFMTlybFRMVjFra0VKNHJEdWRVN1U5YXJpZTV4?= =?utf-8?B?OUhjQnF2MzgvTysyV3d4cmhEQVNLcU0zb2hobHRrTEl1Y3Bzd3lmTjJISVNt?= =?utf-8?B?RzJZeFhCMkxqWVdnNGJuSDJaRFViOWkrYzNMUnBPYWRaYWpCUndoVnIzZ3NT?= =?utf-8?B?cjRxR0tMU3FhRE1va1ZCODlMcnR5Um9vb25nQVdQOXJKQkYwL3VLR29lN2JO?= =?utf-8?B?SXZYMTFySS9meWQ0NWZ3Qk5KT2NRWFRic2NUcWxiRG9hemtyc0cxV2ExR2pl?= =?utf-8?B?Q1lJRmhEV1V5a2Mra1Q1WG1mNW1BN01hbmNia1JzRUcyTThGWGtLZGFHbEVx?= =?utf-8?B?YUxkSHExL2ZpYXZMN2pyUVp5aFc1UllzbzV2ZXpsejVBeEkxUmpvWE9ieEdj?= =?utf-8?B?d0V5dXFaSC9mZTVkZUNxdEZSdVNIM2NBOHc3aDdQTXVrRERLemlEd1U2enVF?= =?utf-8?B?V0tnMXdIR21sSngrdUYrUktnVHJHNWNxdVhWVlJ5dU00TkFPNnNUL0lyVmhh?= =?utf-8?B?bk9nTitVMmUyVUc0ZUFGaTcvOWFEM0REdnFFamZ5Q0FESFhlV1J3L0I0V0VE?= =?utf-8?B?MFQ2dVRpU3JaQ0tUeUh5MEdsUlJ1UUhETTFvYVl3bHNSeVM4by9Td2N3RE1o?= =?utf-8?B?WEtuRFNUUm5DTldsR0Y3RXdldWV4Tm5yc1NjV2F4ZEY1Zk8xZDZMZDRNS01Q?= =?utf-8?B?cHhaZXpHWHhmcSttbXJwNVppMlducVdtSmhUTVNjNVc4TDhzelNzelVhRU5B?= =?utf-8?B?NjF3OUQ1ZnZlTFh3VThHOXBjNXE0QXh4TnVJS1d2UDNyNGNLWDJmWklnYmJn?= =?utf-8?B?Z3hydkhmNTRyeU8rblo0bGd1TU1Zei91VEFudDd6Mk9oRHhBTU9DMFB2clcw?= =?utf-8?B?U0NOWUhsNlpBaklpZkZVSy84STV6UlVxQXdNNEVaTUxONVIrUXZ3clZISDVn?= =?utf-8?B?V3MyS2lCdzR2TlU5SkFSYTZ3NkcvSDlOd3lkWVNuMzY5alo2dEc3MUlNV012?= =?utf-8?B?S0RiYmZ2MW5yMmZoc0FwMFBqVXlBM1h6Y1dwdndJZUEzVGJVN0VTTUVzNERS?= =?utf-8?B?ZjdjaGJmMWdtb2haekJMRE5wVG9vWjZBVkUvb21VUDhSenVPUlNrbktaQTF3?= =?utf-8?B?cm5zRFB5WHg4L0Z1N3p2NFhSY3RCc1ljTzQ0Yzh2eDRJSzE3cVg3MFY3RjNY?= =?utf-8?B?YzAxWDBXV1o5WnhPVm1EOFRtYm9uSW9HN1hZRWppa0RFRjQvSzJBbWZsejh5?= =?utf-8?B?cHQ2UjFUNHVEY2MyNjZVRXBIYXpFTG03QlYyYUxhaDV4OTFwNHJOZGZ1d3V0?= =?utf-8?B?NDJaS0I1OFdMb2U4LzlNUFhQNjJjOXp0cGM3WDN3ODRIUW9zdVcwTVRoRzlG?= =?utf-8?B?ZDlBNEs3RFg5cGVEUDRaRHl5NVdoZEJBRzhUcENZQzBzcEM5REk2UzFZamo2?= =?utf-8?B?dU10VEFRNVFCVGtDTnBUSXh2V2dUeUZ1T2lVem0yU0RXeE1sL1JHSEJQdkpN?= =?utf-8?B?WEpkNVJubTd1ZDdzTE9TbDI1cjdRQ0pwdDVIaThHMlhqMTNQK1QrejQwWUUz?= =?utf-8?B?Wmp0UHpKZ2xuZTA5L1JIVFlLK01LaVJQTFVJaUZUbzRhK29NbEwwMmN3MUZU?= =?utf-8?B?KzFuRVkrUEtlRzJBcVpQcU5jWnVCTmNCNUJINVpVUUVqbzFaRHY4VERLbUdh?= =?utf-8?Q?rn8Pj5zNjvuiTR/JXHd6t0rqg?= 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)(1800799024)(376014)(52116014)(366016)(38350700014);DIR:OUT;SFP:1102 X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Tk9Cc2dHaURXclYvaDZiL3FkYWhEc0c5Zmg0NjI3UTAramRxbWM0eU5XaU1Z?= =?utf-8?B?ZE5xNjR2bUNQM214eWp5SCtxYllZTWUzR3ZZSHZMSlZXSFh6Um9tQXhTUUxh?= =?utf-8?B?M1EwRnJZaS8yMXd2ZVMvd09Hek05TC9rREg5c0pyRXQybzRTZEJqZ2k5K2Vh?= =?utf-8?B?em5MOXR2cmVnRVArL2tuRUc2VFp2eFNzWnVka0VmdXNMZUhoV2ZNTTdZZEU4?= =?utf-8?B?d3BVV3lMUlVXOW51OUZsNHdma0pHY0NMc05PQmNMT1oxdTR5NmFpZmlUZy90?= =?utf-8?B?ODdScHNoK25MVml2a1ZkTlh3M2RsSVdKTTUxOGwwcjBGRzBIUUdLdWVQUlJC?= =?utf-8?B?MC9MbVQ2S3FQZlVoQzhTbEljMHM5RUNpcU80b3pBbTdCNzN1SGU3RW9FbVAr?= =?utf-8?B?aDRBVysyVUVmTTJ5OFM2M1M3MHlFL0c1cTU2dVd4SWZBSWdNd3FWVWpSRDh3?= =?utf-8?B?UFlFUnFXanhiajJVSzNxenJDNkJCS0ZqTVlOMDdNM3JMMlNRZmZiSXU1cTRa?= =?utf-8?B?YjhCUklmYjhhcHJtRW5uN3M0K2ZLU0xocGNkYmxuMHRQMWlpWTA2Uy9LM2E3?= =?utf-8?B?TTJoMlZZdzZ6VmNpeERqOTVRS1RFKzg2YnRna3ptZkxSdjNJaFZjQlMwMkpx?= =?utf-8?B?cHVkbGpaOEhjQ2h3UDdya2FkNnFTcVJ1MW5YNjlqMGFpOU1JWGpKNUQyK2g5?= =?utf-8?B?YWFoR1FLYkVIdDhGdTh1Yi9ReHNtRk1XeUVXTjAwZytwcmoxMEpTamxsOXdV?= =?utf-8?B?ejZaQ3piK1d2TVFCSXRWMWFlMHNwMitEcXZSbEpGNWpvMGNhY01TaUpjYXBs?= =?utf-8?B?eG5lNjI4K2g0a1ZjZnM3QjM1RXpqQlRYcnE5cXFuL0xmbkdIcE9oUVJ5K3Vu?= =?utf-8?B?dFZSZi9JbkdXcjZHOEE4Tlp4b1RneWZCMUc3U3ZtYXNPTVNqdXNWK29FZTRn?= =?utf-8?B?VEVObUV6MDNraGFUblVMYy9yWlVsckIyeHhRZ0VZMlhpdTRpSC9vQnJhT09a?= =?utf-8?B?M1NoOExQdmN3QW9qQjVyZjc4eGppVDB6dHB6QzI2WmM2Y2JKcE5CaG5Pd29u?= =?utf-8?B?UW90RVJkNzNtbHdWbUE0NjNLM1hKdVE4VzBBZ01pSFVyQTVmK0M4Z2dTSHhS?= =?utf-8?B?eUF3M1pQdVFTdHJFaEhONVZ5R0daZG03R3ZnQjl6SGorRFNhMUVkVVN5bnJx?= =?utf-8?B?UG5rZDFYM2NPTWFZVktOVzh5NmRIN1VkVk5HdzQyUXhmMzkvYmpQOUF3dzIy?= =?utf-8?B?RmpVTXN4V0dTcDRiYTdIQSs4cmVzNU9uSzl2ZDljL29tNWFDTElNb2FsVEcx?= =?utf-8?B?NklwdEl5VUhzeHJmY3l1VmJSeW1TVmdQN1lqM2locGllQ2xSVk5DT1lVOEUy?= =?utf-8?B?NGw5ZitTNHE2OGlxVStLL0F2ZFVsMlRJcGRRbTVpOS93N3hZOUVueTlYenFu?= =?utf-8?B?TFVMSkg4NmY1SWVhTU9mVTMwd05tbnFIMDhheUxTTWlBcVBXSnBSMlhxck1v?= =?utf-8?B?YkJWYVE1MUZvamNDN0k0Mms4Tkh6Mm9DTXBzSmtGYlNnK2NaWDNVZlpPdDVF?= =?utf-8?B?R2JYbWl0L0VRdmxrWXdMRldaTnZJbjBCN2JDOXlaaTZLWjVtR2FpYXNkMjRW?= =?utf-8?B?OS9nbmN1cEYyRjkrOFdQWHBWVkJUeUMyT3g0V0IxdzZzNzFyQXBpWHk5V0pm?= =?utf-8?B?V05relArQUNYbnNHUmUxRGlvWGRzMHVwU1gzUURmR1pTZit2eHhUSlJSRFFx?= =?utf-8?B?VW4vNFFZQkVJL3hBVDRVYXFKdTlic09ZdU5RMFE0Nzd1THF0S1dCdjZlUWps?= =?utf-8?B?S1hLVkJ4d1Z4d2tnT2VtUllldFNrWjk2Tm1zVmdqbm96Y1RXWHJSeCthdi9X?= =?utf-8?B?RWQ3K3ZpNEsraFpxWVAybVE1b2dJa1Z0YlRtQTBMbkJmVlUwRDlqL1cxejQr?= =?utf-8?B?WDRuNWpIZHREckJkVGMxMWJSaDA3M3psSDBzd01CNWtDcVhWOUI5OFNSOVEy?= =?utf-8?B?Qk9LOENoc3cySFVLcy9aVnFIcTRwV2d3MXdJTmlhTWFOMFlwc0VLL2VTY0Vq?= =?utf-8?B?Vko5QmVKYW5DZ3BvTlpDRW1qbkI1WHEyajVtVFlFT2s4Y1BBc1FwTGlJS3BG?= =?utf-8?B?aGZCengxejhaZDhvN05ORkhkMjFOS0tNcVV3UnEvS0d3dkl3UHNzN1VpV2RW?= =?utf-8?B?bDVOZ1RBSU1RU1JzV0IzeGxjUElRVWpSM1RIOEY0WnRnZVdPeXVmWkVVaDhu?= =?utf-8?B?MmxqMGV0SlZLUlQwWUZHaWg4NDRaZjVxdzNSdkU0bENzWmtyUGtvYW5FK3Ni?= =?utf-8?B?d24rc24yMy9sTFEyeFAybVlOSDFYYUZrUzlqK1RUM0xXTjN2UkFBZ3ZtVVIv?= =?utf-8?Q?53ZwWHnZ3/BMKJCo=3D?= X-OriginatorOrg: touchnetix.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6841690b-d196-4e9a-48ca-08de5cf964b6 X-MS-Exchange-CrossTenant-AuthSource: LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 16:38:54.0231 (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: M/Dhxll5ZsLSPh5ENoaSuEhIhA6NHIqtxqpcryhAPVn3U1bwNE3Fu0IdDbJ04EfzV2JuIUsAnZ5Ep6OXD4J2+WWyYMDjsfQuFk0sGx1WRpc= X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO2P123MB3824 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: SU_ruABJoiFc2U1tqCmHpK-06Fxt0OzMji2Im92LXOU_1769445537 X-Mimecast-Originator: touchnetix.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" --- .../bindings/input/touchscreen/tnx,axiom.yaml | 70 ++++++++++++++++++= ++++ .../devicetree/bindings/vendor-prefixes.yaml | 2 + 2 files changed, 72 insertions(+) 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..7b532471c17f --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/tnx,axiom.yaml @@ -0,0 +1,70 @@ +# 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 + + reg: + maxItems: 1 + + interrupts: + description: Both IRQ_TYPE_LEVEL_LOW and IRQ_TYPE_EDGE_FALLING are sup= ported + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +allOf: + - $ref: touchscreen.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + touchscreen@66 { + compatible =3D "tnx,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 "tnx,axiom-spi"; + reg =3D <0>; + interrupt-parent =3D <&gpio>; + interrupts =3D <24 IRQ_TYPE_EDGE_FALLING>; + }; + }; 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 From nobody Mon Jan 26 22:57:56 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 534B8344031 for ; Mon, 26 Jan 2026 16:39:07 +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=1769445551; cv=none; b=F8EAtXJYKzJOKeCvlo2OdS5QGjEAOIkvWqC5lZX139yAUv1tVuHDwG4OmwDJqcHcibqgWxFom1dmgwyUquPRW/PhdlgkBekO3J9sAY9nLnw0/LugAeMaT6qx8smwpIrr8KaB38sqktmC0AS/VPLXuNOA6X4vOe6BlIzwPQ1+wbs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769445551; c=relaxed/simple; bh=ehs/TW5o6C93FsFDJMKD2VLUaEgWLWPNwagtvHc+SAg=; h=From:Date:Subject:Message-Id:References:In-Reply-To:To:Cc: MIME-Version:Content-Type; b=sum0JquPhWHcOQpRvmpBaDDPyB0fbwzf8ISrmUgU86qqg1oMoHVMX8nQkenUBu6rN0rqrleXdr83ZrGXG/daUWTDqPtfCTdenP4qZ7qFUaUvM7zYdFZZNplD3xWA6gEqEBwLE9wtFgchKKpmniasUrLAng3c4RTnS6QA/uStEsg= 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 CWXP265CU010.outbound.protection.outlook.com (mail-ukwestazon11022082.outbound.protection.outlook.com [52.101.101.82]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id uk-mta-187-4tR-Yqg1OXCJccuPP5d2OA-3; Mon, 26 Jan 2026 16:38:59 +0000 X-MC-Unique: 4tR-Yqg1OXCJccuPP5d2OA-3 X-Mimecast-MFC-AGG-ID: 4tR-Yqg1OXCJccuPP5d2OA_1769445538 Received: from LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:e9::9) by LO2P123MB3824.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:12d::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9542.12; Mon, 26 Jan 2026 16:38:56 +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.010; Mon, 26 Jan 2026 16:38:56 +0000 From: Andrew Thomas Date: Mon, 26 Jan 2026 16:38:24 +0000 Subject: [PATCH 2/2] Input: add support for aXiom touchscreen controller using SPI or I2C Message-Id: <20260126-axiom-driver-submission3-v1-2-d462c4a608e3@touchnetix.com> References: <20260126-axiom-driver-submission3-v1-0-d462c4a608e3@touchnetix.com> In-Reply-To: <20260126-axiom-driver-submission3-v1-0-d462c4a608e3@touchnetix.com> To: Dmitry Torokhov , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Henrik Rydberg Cc: linux-input@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Andrew Thomas , Marco Felsch X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1769445534; l=27929; i=andrew.thomas@touchnetix.com; s=20260126; h=from:subject:message-id; bh=GB50aXuckUvQJOPovqpShsfnLyaN56CEQq5IrTGN6XE=; b=+52g9soMvfXC0DrRBDi99oZfK3TpnS6QK03HHVO6ifIGd7WmZdkthRXYBM35XZTMkBxbzoU6A 8FQcnU+yhdrA8sfHoaaMQK7Pu4d3z3mbEVRrlxnoYJJvbXqTA7RhMCR X-Developer-Key: i=andrew.thomas@touchnetix.com; a=ed25519; pk=GtS7O+T7kMl4PPu344KeKG2xlsaHEzDUFLtOqb5JPPg= X-ClientProxiedBy: LO6P123CA0059.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:310::17) 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_|LO2P123MB3824:EE_ X-MS-Office365-Filtering-Correlation-Id: fa6899a2-2a4e-411f-1310-08de5cf964dd X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|52116014|366016|38350700014|18082099003 X-Microsoft-Antispam-Message-Info: =?utf-8?B?QmRzUWpuTERPQjNMd0VRYlVsdGhia3d5T2s4ZWtKUndHUU03QjlMYkhpd3Na?= =?utf-8?B?QnJHNTFsTVBRUFJiR1duVlhqbGxBZzNuQUFFN0RFajdobHMzWEVxZHk2aHpa?= =?utf-8?B?Lzh4UDI5VlFhZlUwbzhsdC8wNUhTbkZHQVJrTHVRTE5kMThiaFBmWTJyUVQy?= =?utf-8?B?a3BXdGJ0c280dG8zV3ZvYlI3TkRuS3RuMG1TNVZMc0lUYnJSbmJrY0YwazRa?= =?utf-8?B?WXNCSU9rNUJ6UmdJcm1udVNUUFdHc0g3aEVNeGd6bEZvangvK2J2eDB6dDVa?= =?utf-8?B?QUtpeFpJUFN1bU5icEVCTVM1M3hMeVM2RjYxdUNTUTBOeDQrdzZnQ0I2M243?= =?utf-8?B?UVJJQ0o4c2ZPM2t6anU1dExybUJFSktidDh3NjlUdGlNbCt0c1VvTEdpRi9R?= =?utf-8?B?K1VhWnlzWVZtK3lVL2dmSGlLNHh4V2RmMnFHY2h6TVJWNTNjZzUrQ01vNDkr?= =?utf-8?B?cHlYZGNPQmVPVGNYY1g3eERKQ3F4eTVYQ3doWkF2N25VN2J6U2E3dDVlTWc2?= =?utf-8?B?VFQ4TElLWngrdWlObzhNNWpHR25TVmhJaEIrajNaZTJPeWQ2c2ovelRzYURQ?= =?utf-8?B?dkxWajAwN2c1Z3NuTHZ6UmI3ZXltZFc2Yk9sMmw5NzNDVEVDc2s0WEpWRlJP?= =?utf-8?B?OWNod0RpMklXNUJTbk1qekxPbDl6YndIcW1VQzAyb3IyWlgzYXlMNkZOVmww?= =?utf-8?B?YkFESkFSQTc0aFhENllqMjBVdHY3cHlPUFdQY2FLT09Udlo1ZC9hdG1TZU0z?= =?utf-8?B?NHJ5elZvcnZEa0tlQm9IN2lkTW1PMFdoYk9POWZSMldqdFFZRG51TG5FSFBV?= =?utf-8?B?b1JhSU91TkVCZHlUNHVBeTZBbmFBUmRQQnRNTXU5TVBMTVl6OUl1OE5lOUxQ?= =?utf-8?B?Ui83K1I1aGp6K1RyWGhBdVkwTEFIRm92Z2E2REdmOXVoN0RVOFpEQlpPYUow?= =?utf-8?B?eVRWS3puaHhQSWZLd0NTM1BDUVBzd1BncXhVSHRsRFRyZWxUSjlQZE1TNG1C?= =?utf-8?B?WElHNXJqNGozRFlBb1BySFluZFR5UjJROEIxVnFQQnVpWmNzVmJmSUoyMk5L?= =?utf-8?B?ZzlINm1KWGFtZk0vdUFCSzFPQVdsY0ZBWm1FZUdMUWdPcG05azk0Q2V6UzZq?= =?utf-8?B?aytGT0x0K0V2WFNxbGI3RjdSZVFFTHQ0R0EvZzNNbWVXYnRoenZjYlNkWkYw?= =?utf-8?B?LzVkdHNaTUJ1UnB3N1dyWTF3YVQzZ0xpWG1ITjA5dzF6MnB1RmxKZVhaVGtG?= =?utf-8?B?M3JvMFYvMW5iclpFUXFCWG9hT21tWGV6b0FEciszZng4T1F1alEzbUVoUGRp?= =?utf-8?B?TTVjcTV5SERvNFBtSkd4cHJLcU9oUDFGVGFabzI4L2JhWVM1SlFsbkdtSGhI?= =?utf-8?B?bnlLVU5lWStSRXFhdTk3MWxxTWRZaXVrc1dLMXEya0VBWTR6Wmg2ZFdUUlFP?= =?utf-8?B?MlE3TzdEck1jdlBSMW9nRnJpZW5ZRUZaMHJ5ZjBzZmlRVHVkVVBUbEhtUE1L?= =?utf-8?B?UFNQdkNJOFVyeGwwY0VOUHJBdVJzNWJPdU5zL2VwQkNTQWQ0RWNOM2hCbGxh?= =?utf-8?B?Yk10cUhtMGUwMHdab1RIazRYQmVNNG45YmxHWGhweDA0VEpyemdFN2pCQ3la?= =?utf-8?B?Mi9ibnNoR2s2UVZVRGFURkJ1R1ZDSHY2ZzhhWDBlNUI1VHFPU1ZwNmFPdUNC?= =?utf-8?B?Vjhnb0pyL2RseS9HeWl2b0RBb2s4ZmNZNzlKUFNOdmhqUUxpcVh6REI3TE1H?= =?utf-8?B?OVVLcmVCcWZtNmtSTWJPYTRwSDVnUmtxamNHN2NXdThoMVZ3cCt1S2tIV0xN?= =?utf-8?B?UmtJR1JrYkhhdzJoL21QekZ5OTlaNHJtK045aTdHRlJIcTE1czNLd0hrTlZI?= =?utf-8?B?ZXBkcmNGT0ZWWURXNDJ1TTZEOElvVmhZRjdjT3VrS3A2NkpFaVoxeTdsN0NH?= =?utf-8?B?QXJmQnNyVXJxMDFuR3hlMjdHQVlXMkxLelZBN2xUdHZqOFBHMTZwUDVZZDQz?= =?utf-8?B?S3ZldnNzN3RkZnNhbDl1YXRKOEViTmNWcWxldXRycXlLOTFUSkViVDAwZGFq?= =?utf-8?B?RE54MnNJWEhnT2d2VVlZV0FWZEZzMVhGb1ZobUg0RG1pWUp1cm5jOHI0OTdR?= =?utf-8?B?bDJoNWZldXpoQlpLWDFUSjR2dFZVQXRRWE5sY2lxN2RqeEozTm05WHRwdEVr?= =?utf-8?Q?T8Qv42/gQ2CW7k9s53WgRAc=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)(1800799024)(376014)(52116014)(366016)(38350700014)(18082099003);DIR:OUT;SFP:1102 X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZUxpTEVDL0w5NHJzR0xveWpUdmU5OFljcmhoSmZXSDNqU0FDSllrc1hyZmZG?= =?utf-8?B?M3NhT3Zrd1BLVStrZXRmM3pOOTA1M0VVaEdJWWVzZzFKSzEwcGVielBFQzZ4?= =?utf-8?B?UllJV0k5V0tnRnQ4OFBRckxkcnR5MzNqcEQvSUdRb3haVytPZXlZeHdxNjNU?= =?utf-8?B?ZTM0MTh0aVEwUFVFTURKeDlheFJuVGhZdU5vSTlUeDM4a2xHNjJvMWFOSjFy?= =?utf-8?B?bElIK2VTNlpEelpDRk9ZUm5qNis3WHN5cWZmanp6WEROTU81ODZ2TjZtYVNt?= =?utf-8?B?cFo3VkVGTkx4OTRmaUZkZ0FuTG1BWVNPWlBYbFdNbkcvdnFxV1hPRUNWb3J0?= =?utf-8?B?MUJITlZ2b0lQSUZkWWJzT1F6eFFHMmJPbi9JczBBeEc3RWhzb3haenhjQ25F?= =?utf-8?B?UzJIZE8wQTFSQkpmOFd1bDBZVlJyTU9BRkdsWnBNWExWNnVWaGJMWm9sbTBC?= =?utf-8?B?NE1wYnkrV0sybjducFRUbDIxNXdMdVlmQUNibzBPdFZiT0lkaG5OcGZISlFB?= =?utf-8?B?b2hRbkI3NEl0NUxxVytXeERYNVhTSEZCTWtFa3RKdk1YdzEvbFA5SVlDQ3hV?= =?utf-8?B?L1U3dTlYYkVCMVg4aTJsc2NrcXVsT080d0lBeGxxaUs1TGRHTUJFZ1NBZDAy?= =?utf-8?B?aStUdGc5UGl2OWVJL0JjN0pRVXkzOU9LeUF1U0FnLzVDTVNneW1CdlQ1U1Qz?= =?utf-8?B?eDRRSTZFU3dKMldMeTh1Uk95TjlZS0xsamVheFhQL3d4VWdEVWZzK2xEalpW?= =?utf-8?B?L2xBUC9EaWx1cE5kRnRIQmdMUGs5V0Y5R2FoenJvRmMwbWM5MitlcXBXYmRx?= =?utf-8?B?SWY5VHJKc3ByWUdHeFJkY3lUamRRSEQ0dEZ5MTJsUU0vZVFCTVB0TXViM1Ju?= =?utf-8?B?UUF3SytzWmxMMDNQT3hJeUlSeTBmSm9mZVpsa3ZkVHNQZFUzU2E0aDlQUTZM?= =?utf-8?B?amprdjQ2WEJqQzVRMmhaV1VoY0J4SWtrMGJqbXpvcDhJbkszQkVnY0JYRHh0?= =?utf-8?B?N0JTSHlyNWprckwvL2xJU09qQW5VTEhSazk2QmQvUmlDdHVIWlRIcmxkWUh0?= =?utf-8?B?dzE0V1NDQ3cxVVVsMWVUam85WTRpTXlYcHVKcXhYQW9hSWZCMG9XVTJxSTY3?= =?utf-8?B?UW9VZUlJWGhnMk9LaU9RT1ZjK0JJcHdnTy8vYkc5ZGFKdVpNSlFOdnBTRWdI?= =?utf-8?B?WFc3NlJXdit1ZjJWMmFXWFJSdklLVWdaNEVIUFp2aTZZYkdubUhtV2o5Ymha?= =?utf-8?B?aHI3ZTZQeUZ6VW1sNmZXQ0k2aVk3QWREVFJSY3dFSnlvbG1obWkybWNaOVNZ?= =?utf-8?B?Yi9HaWVmRDVXY0Y0OUpBVitNcUdFT1p2REw4RHVnSnBhUjJveEFldVE1eTVt?= =?utf-8?B?VGRDK3VNUFV0M0dzWElZb0Njckc1NVFoUysrcGdpNTZrMlMzaVA0ckJwSEg2?= =?utf-8?B?L0ExOTZoZVJQWDRtNDhWUjlqeDQzNEg3c1d3YU9JK3BzcHRRTmFyZlJkUHd3?= =?utf-8?B?SDQrK1ZDbWFXbXh0azdZZWtjSjJ1ZG4wTUxHWTVRVGVWcWcwTWRDNXYwOG9z?= =?utf-8?B?M09Ga1QwVjBoMGpLeHBrQWE3QXhwa1B3cm93NmhnYXpxQWVnZW1kU1VWN0dm?= =?utf-8?B?MWM4TStSN0NLRzdZS2JMZm9yWHZwcVFLakdBU3p1ektGdGRueTMwNkpyWmxC?= =?utf-8?B?N29rZXZ2Q3ZXSXVLQW9ra1hFVlJMVHBWS1YxaGd4bWFUOVhOLzdUcTVHVVhY?= =?utf-8?B?aW12ZE1NTFcraTZrM2c2K2xIcXpiZ083NFRROTNOMjNmU29MeVRBN1d6Zzh0?= =?utf-8?B?SE8zMk5xL1ZjelVON0VOYnYzTllleHZUMzlmZXJxZk5Ub2FKMEpyR0R3SnZD?= =?utf-8?B?NXpaWUpwYTQ3NThmMVVWcFp2QUw1OWpnWlpURC9ldUhUc0ZkSCtRYnVyM3R5?= =?utf-8?B?dEdaT1Q1ejN1bDg2cXNDN2J5WFdlWmMvTy8zVVh3ekRUeHZTcXNhYmxCQ3FH?= =?utf-8?B?K1RDaEFsS21DcGc3Wi9QVlkvTzBUcnpzb3BORW1mL0FHMjJNWWVpRzhjcGNF?= =?utf-8?B?WmJ5KzZDZ3kzQ1lOMXM1ZWxjS2tueHNiRHNRNC9TWHRRK01LamxqSkZ6WmU3?= =?utf-8?B?MG1GTEpZRUczQVBIVHVEbE8zbU9tUXk2dnVlTkxRZHNJaGQzT2xXS0xaY0NY?= =?utf-8?B?a3loSFY4OG9ldldPVzVYbnBxa20yZEFuQ0JPc1dsQWMrcWE0bFZqaldGYWt5?= =?utf-8?B?OE95RFpGTDB5L2JQRDR1M2JxYWNOOGwxczlqckMzWDNSTlNLRnBJMXRzOGxy?= =?utf-8?B?c2Y2NWEybnQyL1h6TVhuV1BXeGNrWmlGRldmbS9YdlBNZXlZSFF5Sk5TOFBY?= =?utf-8?Q?LHiWQR5xQiljwkwI=3D?= X-OriginatorOrg: touchnetix.com X-MS-Exchange-CrossTenant-Network-Message-Id: fa6899a2-2a4e-411f-1310-08de5cf964dd X-MS-Exchange-CrossTenant-AuthSource: LOYP123MB2701.GBRP123.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 26 Jan 2026 16:38:54.3232 (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: VmRVaJRcG6jqMM2XESLsQHK3tWo1Qd+m7+UOvk8nh+XTL5P1es6AKRNHlcbSO3KxGt+hALNjihfQwCe79kVJuPP4Xf33lhmgfq/WaHGVAhA= X-MS-Exchange-Transport-CrossTenantHeadersStamped: LO2P123MB3824 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: IL5nODYHMfL6dCtn6R0DOFkll5mVCSM-yxFLBq58cew_1769445538 X-Mimecast-Originator: touchnetix.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" --- drivers/input/touchscreen/Kconfig | 25 ++ drivers/input/touchscreen/Makefile | 3 + drivers/input/touchscreen/axiom_core.c | 473 +++++++++++++++++++++++++++++= ++++ drivers/input/touchscreen/axiom_core.h | 118 ++++++++ drivers/input/touchscreen/axiom_i2c.c | 150 +++++++++++ drivers/input/touchscreen/axiom_spi.c | 155 +++++++++++ 6 files changed, 924 insertions(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/= Kconfig index 7d5b72ee07fa..d27292ccabc9 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -162,6 +162,31 @@ 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 + +config TOUCHSCREEN_AXIOM_I2C + tristate "TouchNetix aXiom touchscreen (I2C)" + depends on I2C + select TOUCHSCREEN_AXIOM_CORE + help + Say Y here if the aXiom touchscreen is connected via + the I2C bus. + + To compile this driver as a module, choose M here: the + module will be called axiom_i2c. + +config TOUCHSCREEN_AXIOM_SPI + tristate "TouchNetix aXiom touchscreen (SPI)" + depends on SPI + select TOUCHSCREEN_AXIOM_CORE + help + Say Y here if the aXiom touchscreen is connected via + the 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..89a845ab90ba --- /dev/null +++ b/drivers/input/touchscreen/axiom_core.c @@ -0,0 +1,473 @@ +// 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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include "axiom_core.h" + +static bool poll_enable; +module_param(poll_enable, bool, 0444); +MODULE_PARM_DESC(poll_enable, "Enable polling mode [default 0=3Dno]"); + +static int poll_period =3D 10; +module_param(poll_period, uint, 0444); +MODULE_PARM_DESC(poll_period, "Polling period in ms [default =3D 10]"); + +/* 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/ts"; + + // Multi Touch + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, 65535, 0, 0); + 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); + + // each report id in u41 can be configured separately in u42, + // to keep it simple have all reports ids be touch. + 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) +{ + struct u31_usage_entry *entry; + u16 report_len; + u8 *ptr; + int i; + u16 w; + + 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) +{ + struct u31_usage_entry *u; + const char *variant_str; + char silicon_rev; + int err; + int i; + + /* 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); + + silicon_rev =3D (char)(0x41 + ax->dev_info.silicon_revision); + + 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"; + + 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); + } + + 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) +{ + enum u41_target_state_e state; + u16 target_present; + bool active; + u8 offset; + int i; + 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) +{ + u16 hdr_buf =3D get_unaligned_le16(&report[0]); + struct u34_report_header hdr; + u16 crc_report; + u16 crc_calc; + int err; + u8 len; + + 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 input_dev *input_dev; + struct axiom *ax; + int err; + + 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); + } + + 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_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"); diff --git a/drivers/input/touchscreen/axiom_core.h b/drivers/input/touchsc= reen/axiom_core.h new file mode 100644 index 000000000000..8ca46200bede --- /dev/null +++ b/drivers/input/touchscreen/axiom_core.h @@ -0,0 +1,118 @@ +/* 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 + */ + +#ifndef __AXIOM_CORE_H +#define __AXIOM_CORE_H + +#include + +#define AX_POLLING_PERIOD_MS (10) + +#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 { + __le16 target_address; + __le16 length_and_op; +} __packed; + +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..93b445f4ce54 --- /dev/null +++ b/drivers/input/touchscreen/axiom_i2c.c @@ -0,0 +1,150 @@ +// 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 + */ + +#include +#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) +{ + struct i2c_client *client =3D to_i2c_client(dev); + struct axiom_cmd_header cmd_header; + u16 len_op; + int err; + + put_unaligned_le16(addr, &cmd_header.target_address); + len_op =3D (length & 0x7FFF) | (AX_RD_OP << 15); + put_unaligned_le16(len_op, &cmd_header.length_and_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, + }, + }; + + err =3D i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err < 0) { + dev_err(dev, "I2C transfer error: %d\n", err); + return err; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return err !=3D ARRAY_SIZE(msgs) ? -EIO : 0; +} + +static int axiom_i2c_write_block_data(struct device *dev, u16 addr, u16 le= ngth, + void *values) +{ + struct i2c_client *client =3D to_i2c_client(dev); + struct axiom_cmd_header cmd_header; + u16 len_op; + int err; + + put_unaligned_le16(addr, &cmd_header.target_address); + len_op =3D (length & 0x7FFF) | (AX_WR_OP << 15); + put_unaligned_le16(len_op, &cmd_header.length_and_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, + }, + }; + + err =3D i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err < 0) { + dev_err(dev, "I2C transfer error: %d\n", err); + return err; + } + + udelay(AXIOM_HOLDOFF_DELAY_US); + + return err !=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 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_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..a7d9d3dd66ce --- /dev/null +++ b/drivers/input/touchscreen/axiom_spi.c @@ -0,0 +1,155 @@ +// 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 + */ + +#include +#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) +{ + struct spi_device *spi =3D to_spi_device(dev); + u8 pad_buf[SPI_PADDING_LEN] =3D { 0 }; + struct axiom_cmd_header cmd_header; + struct spi_transfer xfr_header; + struct spi_transfer xfr_padding; + struct spi_transfer xfr_payload; + struct spi_message msg; + u16 len_op; + int err; + + put_unaligned_le16(addr, &cmd_header.target_address); + len_op =3D (length & 0x7FFF) | (AX_RD_OP << 15); + put_unaligned_le16(len_op, &cmd_header.length_and_op); + + 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); + + err =3D spi_sync(spi, &msg); + if (err < 0) { + dev_err(&spi->dev, "Failed to SPI transfer, error: %d\n", err); + return err; + } + + 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 err; + + /* 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"); + + err =3D spi_setup(spi); + if (err < 0) { + dev_err(&spi->dev, "%s: SPI setup error %d\n", __func__, err); + return err; + } + 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 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_VERSION("1.0.0"); --=20 2.43.0