From nobody Sat Feb 7 15:40:02 2026 Received: from mx0b-001ae601.pphosted.com (mx0a-001ae601.pphosted.com [67.231.149.25]) (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 76143436367; Thu, 5 Feb 2026 16:49:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=67.231.149.25 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770310143; cv=fail; b=m/pEttShU3rgVgyNu5T+5s/2vIt9qvF0RtTeIb2Z2D3ua+HgVFP8EVVujirAYgamdQLayrrzyyVVVB59W+JgpEWfN4ft9a/cyOU2clWymw5GqHWKeKdDcniQyKAqD8mWYstL794qhteP89T36P19x4YN0vGMZpp8LVA9l90oDio= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770310143; c=relaxed/simple; bh=syeK5qRhMWTmAyEA0HOPIFBsDPT/C4y2bSDaGzRBDus=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=qeyJDKfwIvLTqjzCh0vXcuuvqK4dIrPXdmjUbBh4eiHltAdUC2SwF02KtjtxstMOuV3j+pwGMkFaKWNZdVTUjd96Fqp/1CYx0hMjnvLyv0IwN9ykCuP8zATmiRfRtYuEiFftZ1nxzDiqBLxjdMfh2CCS0fe0dLb+NASvuDDAkE0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensource.cirrus.com; spf=pass smtp.mailfrom=opensource.cirrus.com; dkim=pass (2048-bit key) header.d=cirrus.com header.i=@cirrus.com header.b=fJJo1Krp; dkim=pass (1024-bit key) header.d=cirrus4.onmicrosoft.com header.i=@cirrus4.onmicrosoft.com header.b=s11H5H/V; arc=fail smtp.client-ip=67.231.149.25 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensource.cirrus.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensource.cirrus.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cirrus.com header.i=@cirrus.com header.b="fJJo1Krp"; dkim=pass (1024-bit key) header.d=cirrus4.onmicrosoft.com header.i=@cirrus4.onmicrosoft.com header.b="s11H5H/V" Received: from pps.filterd (m0077473.ppops.net [127.0.0.1]) by mx0a-001ae601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6154k5r6552672; Thu, 5 Feb 2026 10:48:47 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s= PODMain02222019; bh=/317Fy2irVb8Pjy49zOFXC/WatcjKK+1SLxoRtQusOg=; b= fJJo1Krp8yOD6my3uxdQjYzhYPLEY1lqcsNqK89TC9Lbp1BNMLIkhoNDHJTUHycM vQp22A8I/ETL7SmPQxdPv0dphiJZ7S5b5FJupm/59IslUoVl+Llh21xEVCYeW8P0 RZuhSUPvMOEtBr6wZ+DMcVTFDyPU9VLzycYbMdkp3lHZPH/uNlla19IVR3VLYZIZ zlBJRkMr5xUgfjv6iiTldQ4Q4C7ZfXxKkA5lbU6KyQhydKD3DUofhO/7g80+gI/m k0iC3RW7ffn6oB5DYeyqedf2jx4jDT/UHLDFBTBNB6pNjlEZqDK33HL5pIGrz72a D+WhlnrFSTqBHBbbEm9oMw== Received: from co1pr03cu002.outbound.protection.outlook.com (mail-westus2azon11020078.outbound.protection.outlook.com [52.101.46.78]) by mx0a-001ae601.pphosted.com (PPS) with ESMTPS id 4c1g12x7vv-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 05 Feb 2026 10:48:46 -0600 (CST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=xNYOckYJIUAldzfdtfi8RzoLduqYXAY/iDcWV5qwp6q5rJauFFRmSrucer1eilxPJ9UswuwHlB7A04w3H9o+MdzcbPbck+E9dtav/7a7wZON7RIpaL1rcgGrUoaB39cawACai786/T5FBlavNzGwA62OsPMzA1YwgKBcWfzcoPmd1QjlFz+Acis/pHZTGd475fN8MkSQY4Ayl1+CWRh5Y3QsAXlBIVPfJ4LZMw2xxHs+meyviT7ijTbyp8+/2Z3DO6/ySESmbzceCBXH1HK2XuewRMZMZjSFf0kTrrF8qK8ft7Vg93a0DexBF7/15L4XdJ7darJ69lLBswokMo/mLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=/317Fy2irVb8Pjy49zOFXC/WatcjKK+1SLxoRtQusOg=; b=kaZIYvfVxAC0KijtsxuQLUMcPUwIP4KbPUg0ggdBNV17hmoTYL9PPN147uJyPyQNpXZm36d8SONkRZvoS/PmOCYAJzkTsKvrAxFH6Atx82EQD5kFsU8MJp+3AWEZJZ32m45yHoprvq0UXrkKS8bMcA/vsw+gYw5P1uOQIRD0lh3Zcyv9B6Dys3fnkq8Dlofe4hEetr4az7LKp1kUDYf//I0c3H3T9ruWt8JvnGw/6Sx6fHgHEPL9up2B3U9nlkxu71JSa2xfprT+v5vBye8EgGF12dw+hPH1PUcLMkiZjvNkJGwtQ0UhAg2JiwpOQvTodnXpWNpEmVd+gdVvxGN6MA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is 84.19.233.75) smtp.rcpttodomain=cirrus.com smtp.mailfrom=opensource.cirrus.com; dmarc=fail (p=reject sp=reject pct=100) action=oreject header.from=opensource.cirrus.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus4.onmicrosoft.com; s=selector2-cirrus4-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=/317Fy2irVb8Pjy49zOFXC/WatcjKK+1SLxoRtQusOg=; b=s11H5H/VBQ6Ixh/9cs70CDO69EFhGUS2Ehddj7UH4nV99/UUbuVelP8moDXRofWGFZjjBr60rfvyxCH07dA3uPLADelPQUDk9CTNSsTYqZ9H4L/YtLnuQcqcF5cNs6xpFlJbEO6tNDTu71tFRIdwqr76Mo5XozqH3INWKhCgOt8= Received: from MN2PR15CA0065.namprd15.prod.outlook.com (2603:10b6:208:237::34) by LV9PR19MB9184.namprd19.prod.outlook.com (2603:10b6:408:2e7::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9587.13; Thu, 5 Feb 2026 16:48:40 +0000 Received: from BL02EPF00021F6C.namprd02.prod.outlook.com (2603:10b6:208:237:cafe::8c) by MN2PR15CA0065.outlook.office365.com (2603:10b6:208:237::34) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9542.16 via Frontend Transport; Thu, 5 Feb 2026 16:48:19 +0000 X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 84.19.233.75) smtp.mailfrom=opensource.cirrus.com; dkim=none (message not signed) header.d=none;dmarc=fail action=oreject header.from=opensource.cirrus.com; Received-SPF: Fail (protection.outlook.com: domain of opensource.cirrus.com does not designate 84.19.233.75 as permitted sender) receiver=protection.outlook.com; client-ip=84.19.233.75; helo=edirelay1.ad.cirrus.com; Received: from edirelay1.ad.cirrus.com (84.19.233.75) by BL02EPF00021F6C.mail.protection.outlook.com (10.167.249.8) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.10 via Frontend Transport; Thu, 5 Feb 2026 16:48:39 +0000 Received: from ediswmail9.ad.cirrus.com (ediswmail9.ad.cirrus.com [198.61.86.93]) by edirelay1.ad.cirrus.com (Postfix) with ESMTPS id B83BB406559; Thu, 5 Feb 2026 16:48:38 +0000 (UTC) Received: from ediswws06.ad.cirrus.com (ediswws06.ad.cirrus.com [198.90.208.24]) by ediswmail9.ad.cirrus.com (Postfix) with ESMTPSA id 9368C82025A; Thu, 5 Feb 2026 16:48:38 +0000 (UTC) From: Richard Fitzgerald To: broonie@kernel.org Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, patches@opensource.cirrus.com Subject: [PATCH 1/3] ASoC: cs35l56: Support for reading speaker ID from on-chip GPIOs Date: Thu, 5 Feb 2026 16:48:36 +0000 Message-ID: <20260205164838.1611295-2-rf@opensource.cirrus.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260205164838.1611295-1-rf@opensource.cirrus.com> References: <20260205164838.1611295-1-rf@opensource.cirrus.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BL02EPF00021F6C:EE_|LV9PR19MB9184:EE_ X-MS-Office365-Filtering-Correlation-Id: b593693f-eac6-4b34-f802-08de64d66a0d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700013|82310400026|61400799027|376014|54012099003; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?R6LB2e7uJvTKWjDae04FKJxLcfEFz7IZd7WUr0dVos/VPnDS18YE+2ZH4tN/?= =?us-ascii?Q?AhG2tkbG8uysiNudDQEaJKbJtz2gTUGS5Zp6A9HpJZwhXl3e+M3niADPkuYx?= =?us-ascii?Q?xcNK7BFXE8/cPETqmNW1H5M9xf7u44LVd0LSRW/RMnrXK/GURkEKEDUcHYM0?= =?us-ascii?Q?k3CcuFlytv77BS4xfX6QQRVBFjMN1BFVOyUsKZsAhR357uCtmrfj/sPi8D9R?= =?us-ascii?Q?Udp0T+qO+j+6Bm8waONypmjrh5XpvusT2TmbnbZtMKfBAeXnqs8Tw1vjqE5T?= =?us-ascii?Q?r6Vc6d83Jn+/aWe8H0+buF3WAiDKsDCetnete84vQj763izrl76cUJMQg+JZ?= =?us-ascii?Q?rKYqBjAqQMNwyXLO6fWOAbVJYtGiAS+sSz68NLYT5h8Ulv+xWJobGPD00qzi?= =?us-ascii?Q?4YJlQmAOatxhPQ2HJzN1LlQ2tLQD8pX30tTo28shEZnC/sG4kD8ty4F1uqMs?= =?us-ascii?Q?GclYSs/xLeRT0pIBwqSLQefORan4WSbZ6XBW1CXsNrRh8M1iWm10gOXgnj0z?= =?us-ascii?Q?Bo2OnnVaGd4vRoCJ5a1lRCedGGRCcnviCdcrIrx7BbxvlZEfNTC63u+frQrS?= =?us-ascii?Q?Y0rUryGTvHWduIj9VYylW+M6aE6o264EZ0MyCJw1AT9eU9+Dth5nrQQ/97n6?= =?us-ascii?Q?401+G63Qu3S4aMQpypsV9eL3FItDxG8zJZ3WXlbaEGSGP54BIsJ9CbwrgImI?= =?us-ascii?Q?dtalbguXQCQEQ7CPgbgOcIvCOZcEWQ0GbZ+pNEFRAnko4kK+mwmUZhP+Za4Q?= =?us-ascii?Q?OnhJ0aXI3AlApO48tHcePPdv7AvGQKkK8riUaRcFI060XpKES4E/w31tHCWz?= =?us-ascii?Q?Iya0Nq188XC7FJSAlE07N9YoLenGCoehUdzHS9SzmxeJGnQs3kWfZlOlPI7e?= =?us-ascii?Q?tg4qxeaoY9CuVhbE4A9z0p+AZiHzzyM4JXJ6E8QiQOw/04DU51RiCF97Hl1z?= =?us-ascii?Q?OjzhgGlKRvSVbybFpAgvCKyByJWzJWfwyGgEGXMP2X3L9PL75hYTAOfXHjLx?= =?us-ascii?Q?NYAo2VmETSWmxkETJcstbMMD50V17DhTmTvD5uf/jlt+QnbO5rvzSRpoJblP?= =?us-ascii?Q?STCHWKRbAbmtyiGfjfyCThcPsVpeojua1cZPZLVH+pE6wMmIw/CvKcsW6cZc?= =?us-ascii?Q?fz1y0KfE5BkNiyaUZP3MmLXk1nyI7ACR8ulYNc2+XOZPpfYmRphUlPtz7ISJ?= =?us-ascii?Q?6ZQE6fzRmPiZ/SRAjjdErybBlhu6VAaSmasUc/nZR2JBNtVenSvmMzRsvsGL?= =?us-ascii?Q?0nuehdyrGNd09Ocn10Us8yx0x0PqaWbKt/NhPaAO7WYLIVMgx95bbsjAthil?= =?us-ascii?Q?5H3F3ih45DrKG8TAmmWTYGPU/vPmaTGCs0Fmrfw9yn8cKSDSmjyFV7209cna?= =?us-ascii?Q?w/DQ4gfMuNynpswzZIN2RlkQs5iG8HCZXBQJkxsJfzgDWH4rTHh1Qw2MzX6i?= =?us-ascii?Q?smpyYyT3X9Fki7WTkHa+tOKXMx3oBtELwBlAejBlD8QuEY8ZjRLsypfvUeVq?= =?us-ascii?Q?KqMy616U8tX6Qh37N3zsK5Wr8lI/wyQTy6AIjI4lFABLOo9AsU0GfrE/ReBB?= =?us-ascii?Q?d7aEXJnItWZU+Kbv93sNnYId5BmqyvHVEiBWfa4wVRhwYDU+6pUYeXjthNhC?= =?us-ascii?Q?PwcYD+ijJ0683DlCvJ6sntYNciISX5Y/cZH/ym1WnbzIa5L96XCXuRuwV5ue?= =?us-ascii?Q?rBji+w=3D=3D?= X-Forefront-Antispam-Report: CIP:84.19.233.75;CTRY:GB;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:edirelay1.ad.cirrus.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(36860700013)(82310400026)(61400799027)(376014)(54012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: qYnz/gmeQdESlGiMaVL3YkkhDc4xTaBt3tJk04l7DcG/zOSaYNGCv8bL5PliDz51zOu20pkTFHeWZjpH20HY4MOS0Q9xYSGrFI6nKio9VyNJIOOLwXqO7h9W2OAFy8Puco/iY33sdjXP6hQZw04uBzWR0lIZ3XvDQfwU3QYNB9YTh0ZXS/I3VHrjdAQXR/GDqeqqqiPoHH5QCRQPpFza8wtQa3TBJah3USv60B+F1+BfBJBvgcbRb5ZcjljpfJZqL7cvN6uGGYN4x3CS+UFfwjtZmZi74WxqV4dWNa1R8jHjg33aEQv4I6mYoPL8FEp309FLuJkXQLC8t+QirdZhSiek8SUUQuY+LB8eSli0nThXbgiHEIgI+/1BOUHhq3BSFghyS8mCEsPgxV4voiw3Kf3YRvodpLzZ08ddguVDVHBpxwPrMcRTwkiAcERygiVt X-OriginatorOrg: opensource.cirrus.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Feb 2026 16:48:39.6214 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: b593693f-eac6-4b34-f802-08de64d66a0d X-MS-Exchange-CrossTenant-Id: bec09025-e5bc-40d1-a355-8e955c307de8 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=bec09025-e5bc-40d1-a355-8e955c307de8;Ip=[84.19.233.75];Helo=[edirelay1.ad.cirrus.com] X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: TreatMessagesAsInternal-BL02EPF00021F6C.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV9PR19MB9184 X-Proofpoint-GUID: 8AYQLsH2WIgufb7aY9PhzQBMdX36CsBv X-Authority-Analysis: v=2.4 cv=Mdthep/f c=1 sm=1 tr=0 ts=6984c9ee cx=c_pps a=x8fXg9NzY3hbHNzXWQS9+Q==:117 a=h1hSm8JtM9GN1ddwPAif2w==:17 a=6eWqkTHjU83fiwn7nKZWdM+Sl24=:19 a=z/mQ4Ysz8XfWz/Q5cLBRGdckG28=:19 a=HzLeVaNsDn8A:10 a=s63m1ICgrNkA:10 a=RWc_ulEos4gA:10 a=VkNPw1HP01LnGYTKEx00:22 a=w1d2syhTAAAA:8 a=RfwS6-uD395bjvBFnvAA:9 X-Proofpoint-ORIG-GUID: 8AYQLsH2WIgufb7aY9PhzQBMdX36CsBv X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjA1MDEyNyBTYWx0ZWRfX1xJ9hyNAQQXE VfNxJ0TQUaBoyZbcplj4UtWS8Vyhp62Rhnd0BvL/vsjrTiAbOnI31uJx4K9l3jIsFyGekMnjDcp wVk1KTVf6Na9xY9fanPvAVB2ZprgATXkEYn3ceFmnKeoO3iepcyezjk5YKNcUQt3KtEtpSkvQTw kJhf0+8B7kG2c6ikSsTrkUnEwrk+qYA9y7L2qxokNmSyac+Y1F9ds3ouQfKhGAJ8rlMBszVInhw gLWR0535f9aIiIveTZHNehCw6STgZvZw2jG6sv55PKszFcilULpzfHGSm9Xj1tELHV6jhJtGSwn wM+og8Mv5Swj9mhEkpKN7kEY1k5vlcR7MhllUWl1gFgjrPhNYOMKbT2OulnUr3dOD9DarxrlkVy 3Uk2OyAo6W5gsLVYJ3pigUf6KTOXX494ALxwungbNlRal5F2Pfqo7At4Rk3vgWL72PRUbC5A5Bo GYysCu2qivOkZOs8E8Q== X-Proofpoint-Spam-Reason: safe Content-Type: text/plain; charset="utf-8" Add support for using the state of pins on the amplifier to indicate the type of speaker fitted. Previously, where there were alternate speaker vendors, this was indicated using host CPU GPIOs. Some new Dell models use spare pins on the CS35L63 as GPIOs for the speaker ID detection. Cirrus-specific SDCA Disco properties provide a list of the pins to be used, and pull-up/down settings for the pads. This list is ordered, MSbit to LSbit. The code to set the firmware filename has been modified to check for using chip pins for speaker ID. The entire block of code to set firmware name has been moved out of cs35l56_component_probe() into its own function to make it easier to KUnit test. Signed-off-by: Richard Fitzgerald --- include/sound/cs35l56.h | 37 +++++++ sound/soc/codecs/cs35l56-shared.c | 167 ++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l56.c | 141 ++++++++++++++++++++++++- sound/soc/codecs/cs35l56.h | 2 + 4 files changed, 343 insertions(+), 4 deletions(-) diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h index 5928af539c46..ae1e1489b671 100644 --- a/include/sound/cs35l56.h +++ b/include/sound/cs35l56.h @@ -9,6 +9,7 @@ #ifndef __CS35L56_H #define __CS35L56_H =20 +#include #include #include #include @@ -26,6 +27,9 @@ struct snd_ctl_elem_value; #define CS35L56_GLOBAL_ENABLES 0x0002014 #define CS35L56_BLOCK_ENABLES 0x0002018 #define CS35L56_BLOCK_ENABLES2 0x000201C +#define CS35L56_SYNC_GPIO1_CFG 0x0002410 +#define CS35L56_ASP2_DIO_GPIO13_CFG 0x0002440 +#define CS35L56_UPDATE_REGS 0x0002A0C #define CS35L56_REFCLK_INPUT 0x0002C04 #define CS35L56_GLOBAL_SAMPLE_RATE 0x0002C0C #define CS35L56_OTP_MEM_53 0x00300D4 @@ -65,6 +69,9 @@ struct snd_ctl_elem_value; #define CS35L56_IRQ1_MASK_8 0x000E0AC #define CS35L56_IRQ1_MASK_18 0x000E0D4 #define CS35L56_IRQ1_MASK_20 0x000E0DC +#define CS35L56_GPIO_STATUS1 0x000F000 +#define CS35L56_GPIO1_CTRL1 0x000F008 +#define CS35L56_GPIO13_CTRL1 0x000F038 #define CS35L56_MIXER_NGATE_CH1_CFG 0x0010004 #define CS35L56_MIXER_NGATE_CH2_CFG 0x0010008 #define CS35L56_DSP_MBOX_1_RAW 0x0011000 @@ -130,6 +137,17 @@ struct snd_ctl_elem_value; #define CS35L56_MTLREVID_MASK 0x0000000F #define CS35L56_REVID_B0 0x000000B0 =20 +/* PAD_INTF */ +#define CS35L56_PAD_GPIO_PULL_MASK GENMASK(3, 2) +#define CS35L56_PAD_GPIO_IE BIT(0) + +#define CS35L56_PAD_PULL_NONE 0 +#define CS35L56_PAD_PULL_UP 1 +#define CS35L56_PAD_PULL_DOWN 2 + +/* UPDATE_REGS */ +#define CS35L56_UPDT_GPIO_PRES BIT(6) + /* ASP_ENABLES1 */ #define CS35L56_ASP_RX2_EN_SHIFT 17 #define CS35L56_ASP_RX1_EN_SHIFT 16 @@ -185,6 +203,12 @@ struct snd_ctl_elem_value; /* MIXER_NGATE_CHn_CFG */ #define CS35L56_AUX_NGATE_CHn_EN 0x00000001 =20 +/* GPIOn_CTRL1 */ +#define CS35L56_GPIO_DIR_MASK BIT(31) +#define CS35L56_GPIO_FN_MASK GENMASK(2, 0) + +#define CS35L56_GPIO_FN_GPIO 0x00000001 + /* Mixer input sources */ #define CS35L56_INPUT_SRC_NONE 0x00 #define CS35L56_INPUT_SRC_ASP1RX1 0x08 @@ -279,6 +303,7 @@ struct snd_ctl_elem_value; #define CS35L56_HALO_STATE_TIMEOUT_US 250000 #define CS35L56_RESET_PULSE_MIN_US 1100 #define CS35L56_WAKE_HOLD_TIME_US 1000 +#define CS35L56_PAD_PULL_SETTLE_US 10 =20 #define CS35L56_CALIBRATION_POLL_US (100 * USEC_PER_MSEC) #define CS35L56_CALIBRATION_TIMEOUT_US (5 * USEC_PER_SEC) @@ -289,6 +314,9 @@ struct snd_ctl_elem_value; #define CS35L56_NUM_BULK_SUPPLIES 3 #define CS35L56_NUM_DSP_REGIONS 5 =20 +#define CS35L56_MAX_GPIO 13 +#define CS35L63_MAX_GPIO 9 + /* Additional margin for SYSTEM_RESET to control port ready on SPI */ #define CS35L56_SPI_RESET_TO_PORT_READY_US (CS35L56_CONTROL_PORT_READY_US = + 2500) =20 @@ -338,6 +366,10 @@ struct cs35l56_base { const struct cirrus_amp_cal_controls *calibration_controls; struct dentry *debugfs; u64 silicon_uid; + u8 onchip_spkid_gpios[5]; + u8 num_onchip_spkid_gpios; + u8 onchip_spkid_pulls[5]; + u8 num_onchip_spkid_pulls; }; =20 static inline bool cs35l56_is_otp_register(unsigned int reg) @@ -413,6 +445,11 @@ void cs35l56_warn_if_firmware_missing(struct cs35l56_b= ase *cs35l56_base); void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *= cs_dsp); int cs35l56_hw_init(struct cs35l56_base *cs35l56_base); int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base); +int cs35l56_check_and_save_onchip_spkid_gpios(struct cs35l56_base *cs35l56= _base, + const u32 *gpios, int num_gpios, + const u32 *pulls, int num_pulls); +int cs35l56_configure_onchip_spkid_pads(struct cs35l56_base *cs35l56_base); +int cs35l56_read_onchip_spkid(struct cs35l56_base *cs35l56_base); int cs35l56_get_bclk_freq_id(unsigned int freq); void cs35l56_fill_supply_names(struct regulator_bulk_data *data); =20 diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-s= hared.c index 60100c8f8c95..55c75b9e4172 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -6,12 +6,14 @@ // Cirrus Logic International Semiconductor Ltd. =20 #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -182,6 +184,8 @@ static bool cs35l56_readable_reg(struct device *dev, un= signed int reg) case CS35L56_OTP_MEM_53: case CS35L56_OTP_MEM_54: case CS35L56_OTP_MEM_55: + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: + case CS35L56_UPDATE_REGS: case CS35L56_ASP1_ENABLES1: case CS35L56_ASP1_CONTROL1: case CS35L56_ASP1_CONTROL2: @@ -213,6 +217,7 @@ static bool cs35l56_readable_reg(struct device *dev, un= signed int reg) case CS35L56_IRQ1_MASK_8: case CS35L56_IRQ1_MASK_18: case CS35L56_IRQ1_MASK_20: + case CS35L56_GPIO_STATUS1 ... CS35L56_GPIO13_CTRL1: case CS35L56_MIXER_NGATE_CH1_CFG: case CS35L56_MIXER_NGATE_CH2_CFG: case CS35L56_DSP_VIRTUAL1_MBOX_1: @@ -262,6 +267,8 @@ static bool cs35l56_common_volatile_reg(unsigned int re= g) case CS35L56_GLOBAL_ENABLES: /* owned by firmware */ case CS35L56_BLOCK_ENABLES: /* owned by firmware */ case CS35L56_BLOCK_ENABLES2: /* owned by firmware */ + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: + case CS35L56_UPDATE_REGS: case CS35L56_REFCLK_INPUT: /* owned by firmware */ case CS35L56_GLOBAL_SAMPLE_RATE: /* owned by firmware */ case CS35L56_DACPCM1_INPUT: /* owned by firmware */ @@ -272,6 +279,7 @@ static bool cs35l56_common_volatile_reg(unsigned int re= g) case CS35L56_IRQ1_EINT_1 ... CS35L56_IRQ1_EINT_8: case CS35L56_IRQ1_EINT_18: case CS35L56_IRQ1_EINT_20: + case CS35L56_GPIO_STATUS1 ... CS35L56_GPIO13_CTRL1: case CS35L56_MIXER_NGATE_CH1_CFG: case CS35L56_MIXER_NGATE_CH2_CFG: case CS35L56_DSP_VIRTUAL1_MBOX_1: @@ -1552,6 +1560,165 @@ int cs35l56_get_speaker_id(struct cs35l56_base *cs3= 5l56_base) } EXPORT_SYMBOL_NS_GPL(cs35l56_get_speaker_id, "SND_SOC_CS35L56_SHARED"); =20 +int cs35l56_check_and_save_onchip_spkid_gpios(struct cs35l56_base *cs35l56= _base, + const u32 *gpios, int num_gpios, + const u32 *pulls, int num_pulls) +{ + int max_gpio; + int ret =3D 0; + int i; + + if ((num_gpios > ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)) || + (num_pulls > ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls))) + return -EOVERFLOW; + + switch (cs35l56_base->type) { + case 0x54: + case 0x56: + case 0x57: + max_gpio =3D CS35L56_MAX_GPIO; + break; + default: + max_gpio =3D CS35L63_MAX_GPIO; + break; + } + + for (i =3D 0; i < num_gpios; i++) { + if (gpios[i] < 1 || gpios[i] > max_gpio) { + dev_err(cs35l56_base->dev, "Invalid spkid GPIO %d\n", gpios[i]); + /* Keep going so we log all bad values */ + ret =3D -EINVAL; + } + + /* Change to zero-based */ + cs35l56_base->onchip_spkid_gpios[i] =3D gpios[i] - 1; + } + + for (i =3D 0; i < num_pulls; i++) { + switch (pulls[i]) { + case 0: + cs35l56_base->onchip_spkid_pulls[i] =3D CS35L56_PAD_PULL_NONE; + break; + case 1: + cs35l56_base->onchip_spkid_pulls[i] =3D CS35L56_PAD_PULL_UP; + break; + case 2: + cs35l56_base->onchip_spkid_pulls[i] =3D CS35L56_PAD_PULL_DOWN; + break; + default: + dev_err(cs35l56_base->dev, "Invalid spkid pull %d\n", pulls[i]); + /* Keep going so we log all bad values */ + ret =3D -EINVAL; + break; + } + } + if (ret) + return ret; + + cs35l56_base->num_onchip_spkid_gpios =3D num_gpios; + cs35l56_base->num_onchip_spkid_pulls =3D num_pulls; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_check_and_save_onchip_spkid_gpios, "SND_SOC_C= S35L56_SHARED"); + +/* Caller must pm_runtime resume before calling this function */ +int cs35l56_configure_onchip_spkid_pads(struct cs35l56_base *cs35l56_base) +{ + struct regmap *regmap =3D cs35l56_base->regmap; + unsigned int addr_offset, val; + int num_gpios, num_pulls; + int i, ret; + + if (cs35l56_base->num_onchip_spkid_gpios =3D=3D 0) + return 0; + + num_gpios =3D min(cs35l56_base->num_onchip_spkid_gpios, + ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); + num_pulls =3D min(cs35l56_base->num_onchip_spkid_pulls, + ARRAY_SIZE(cs35l56_base->onchip_spkid_pulls)); + + for (i =3D 0; i < num_gpios; i++) { + addr_offset =3D cs35l56_base->onchip_spkid_gpios[i] * sizeof(u32); + + /* Set unspecified pulls to NONE */ + if (i < num_pulls) { + val =3D FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK, + cs35l56_base->onchip_spkid_pulls[i]); + } else { + val =3D FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK, CS35L56_PAD_PULL_NONE); + } + + ret =3D regmap_update_bits(regmap, CS35L56_SYNC_GPIO1_CFG + addr_offset, + CS35L56_PAD_GPIO_PULL_MASK | CS35L56_PAD_GPIO_IE, + val | CS35L56_PAD_GPIO_IE); + if (ret) { + dev_err(cs35l56_base->dev, "GPIO%d set pad fail: %d\n", + cs35l56_base->onchip_spkid_gpios[i] + 1, ret); + return ret; + } + } + + ret =3D regmap_write(regmap, CS35L56_UPDATE_REGS, CS35L56_UPDT_GPIO_PRES); + if (ret) { + dev_err(cs35l56_base->dev, "UPDT_GPIO_PRES failed:%d\n", ret); + return ret; + } + + usleep_range(CS35L56_PAD_PULL_SETTLE_US, CS35L56_PAD_PULL_SETTLE_US * 2); + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_configure_onchip_spkid_pads, "SND_SOC_CS35L56= _SHARED"); + +/* Caller must pm_runtime resume before calling this function */ +int cs35l56_read_onchip_spkid(struct cs35l56_base *cs35l56_base) +{ + struct regmap *regmap =3D cs35l56_base->regmap; + unsigned int addr_offset, val; + int num_gpios; + int speaker_id =3D 0; + int i, ret; + + if (cs35l56_base->num_onchip_spkid_gpios =3D=3D 0) + return -ENOENT; + + num_gpios =3D min(cs35l56_base->num_onchip_spkid_gpios, + ARRAY_SIZE(cs35l56_base->onchip_spkid_gpios)); + + for (i =3D 0; i < num_gpios; i++) { + addr_offset =3D cs35l56_base->onchip_spkid_gpios[i] * sizeof(u32); + + ret =3D regmap_update_bits(regmap, CS35L56_GPIO1_CTRL1 + addr_offset, + CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_MASK, + CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO); + if (ret) { + dev_err(cs35l56_base->dev, "GPIO%u set func fail: %d\n", + cs35l56_base->onchip_spkid_gpios[i] + 1, ret); + return ret; + } + } + + ret =3D regmap_read(regmap, CS35L56_GPIO_STATUS1, &val); + if (ret) { + dev_err(cs35l56_base->dev, "GPIO%d status read failed: %d\n", + cs35l56_base->onchip_spkid_gpios[i] + 1, ret); + return ret; + } + + for (i =3D 0; i < num_gpios; i++) { + speaker_id <<=3D 1; + + if (val & BIT(cs35l56_base->onchip_spkid_gpios[i])) + speaker_id |=3D 1; + } + + dev_dbg(cs35l56_base->dev, "Onchip GPIO Speaker ID =3D %d\n", speaker_id); + + return speaker_id; +} +EXPORT_SYMBOL_NS_GPL(cs35l56_read_onchip_spkid, "SND_SOC_CS35L56_SHARED"); + static const u32 cs35l56_bclk_valid_for_pll_freq_table[] =3D { [0x0C] =3D 128000, [0x0F] =3D 256000, diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 31dd2f7b2858..2ff8b172b76e 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1179,15 +1179,28 @@ VISIBLE_IF_KUNIT int cs35l56_set_fw_suffix(struct c= s35l56_private *cs35l56) } EXPORT_SYMBOL_IF_KUNIT(cs35l56_set_fw_suffix); =20 -static int cs35l56_component_probe(struct snd_soc_component *component) +VISIBLE_IF_KUNIT int cs35l56_set_fw_name(struct snd_soc_component *compone= nt) { - struct snd_soc_dapm_context *dapm =3D snd_soc_component_to_dapm(component= ); struct cs35l56_private *cs35l56 =3D snd_soc_component_get_drvdata(compone= nt); - struct dentry *debugfs_root =3D component->debugfs_root; unsigned short vendor, device; int ret; =20 - BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) !=3D ARRAY_SIZE(cs35l56_t= x_input_values)); + if ((cs35l56->speaker_id < 0) && cs35l56->base.num_onchip_spkid_gpios) { + PM_RUNTIME_ACQUIRE(cs35l56->base.dev, pm); + ret =3D PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret =3D cs35l56_configure_onchip_spkid_pads(&cs35l56->base); + if (ret) + return ret; + + ret =3D cs35l56_read_onchip_spkid(&cs35l56->base); + if (ret < 0) + return ret; + + cs35l56->speaker_id =3D ret; + } =20 if (!cs35l56->dsp.system_name && (snd_soc_card_get_pci_ssid(component->card, &vendor, &device) =3D=3D = 0)) { @@ -1208,6 +1221,19 @@ static int cs35l56_component_probe(struct snd_soc_co= mponent *component) return -ENOMEM; } =20 + return 0; +} +EXPORT_SYMBOL_IF_KUNIT(cs35l56_set_fw_name); + +static int cs35l56_component_probe(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm =3D snd_soc_component_to_dapm(component= ); + struct cs35l56_private *cs35l56 =3D snd_soc_component_get_drvdata(compone= nt); + struct dentry *debugfs_root =3D component->debugfs_root; + int ret; + + BUILD_BUG_ON(ARRAY_SIZE(cs35l56_tx_input_texts) !=3D ARRAY_SIZE(cs35l56_t= x_input_values)); + if (!wait_for_completion_timeout(&cs35l56->init_completion, msecs_to_jiffies(5000))) { dev_err(cs35l56->base.dev, "%s: init_completion timed out\n", __func__); @@ -1219,6 +1245,10 @@ static int cs35l56_component_probe(struct snd_soc_co= mponent *component) return -ENOMEM; =20 cs35l56->component =3D component; + ret =3D cs35l56_set_fw_name(component); + if (ret) + return ret; + ret =3D cs35l56_set_fw_suffix(cs35l56); if (ret) return ret; @@ -1532,6 +1562,105 @@ static int cs35l56_dsp_init(struct cs35l56_private = *cs35l56) return 0; } =20 +static int cs35l56_read_fwnode_u32_array(struct device *dev, + struct fwnode_handle *parent_node, + const char *prop_name, + int max_count, + u32 *dest) +{ + int count, ret; + + count =3D fwnode_property_count_u32(parent_node, prop_name); + if ((count =3D=3D 0) || (count =3D=3D -EINVAL) || (count =3D=3D -ENODATA)= ) { + dev_dbg(dev, "%s not found in %s\n", prop_name, fwnode_get_name(parent_n= ode)); + return 0; + } + + if (count < 0) { + dev_err(dev, "Get %s error:%d\n", prop_name, count); + return count; + } + + if (count > max_count) { + dev_err(dev, "%s too many entries (%d)\n", prop_name, count); + return -EOVERFLOW; + } + + ret =3D fwnode_property_read_u32_array(parent_node, prop_name, dest, coun= t); + if (ret) { + dev_err(dev, "Error reading %s: %d\n", prop_name, ret); + return ret; + } + + return count; +} + +static int cs35l56_process_xu_onchip_speaker_id(struct cs35l56_private *cs= 35l56, + struct fwnode_handle *ext_node) +{ + static const char * const gpio_name =3D "01fa-spk-id-gpios-onchip"; + static const char * const pull_name =3D "01fa-spk-id-gpios-onchip-pull"; + u32 gpios[5], pulls[5]; + int num_gpios, num_pulls; + int ret; + + static_assert(ARRAY_SIZE(gpios) =3D=3D ARRAY_SIZE(cs35l56->base.onchip_sp= kid_gpios)); + static_assert(ARRAY_SIZE(pulls) =3D=3D ARRAY_SIZE(cs35l56->base.onchip_sp= kid_pulls)); + + num_gpios =3D cs35l56_read_fwnode_u32_array(cs35l56->base.dev, ext_node, = gpio_name, + ARRAY_SIZE(gpios), gpios); + if (num_gpios < 1) + return num_gpios; + + num_pulls =3D cs35l56_read_fwnode_u32_array(cs35l56->base.dev, ext_node, = pull_name, + ARRAY_SIZE(pulls), pulls); + if (num_pulls < 0) + return num_pulls; + + if (num_pulls !=3D num_gpios) { + dev_warn(cs35l56->base.dev, "%s count(%d) !=3D %s count(%d)\n", + pull_name, num_pulls, gpio_name, num_gpios); + } + + ret =3D cs35l56_check_and_save_onchip_spkid_gpios(&cs35l56->base, + gpios, num_gpios, + pulls, num_pulls); + if (ret) { + return dev_err_probe(cs35l56->base.dev, ret, "Error in %s/%s\n", + gpio_name, pull_name); + } + + return 0; +} + +VISIBLE_IF_KUNIT int cs35l56_process_xu_properties(struct cs35l56_private = *cs35l56) +{ + struct fwnode_handle *ext_node =3D NULL; + struct fwnode_handle *link; + int ret; + + if (!cs35l56->sdw_peripheral) + return 0; + + fwnode_for_each_child_node(dev_fwnode(cs35l56->base.dev), link) { + ext_node =3D fwnode_get_named_child_node(link, + "mipi-sdca-function-expansion-subproperties"); + if (ext_node) { + fwnode_handle_put(link); + break; + } + } + + if (!ext_node) + return 0; + + ret =3D cs35l56_process_xu_onchip_speaker_id(cs35l56, ext_node); + fwnode_handle_put(ext_node); + + return ret; +} +EXPORT_SYMBOL_IF_KUNIT(cs35l56_process_xu_properties); + static int cs35l56_get_firmware_uid(struct cs35l56_private *cs35l56) { struct device *dev =3D cs35l56->base.dev; @@ -1712,6 +1841,10 @@ int cs35l56_common_probe(struct cs35l56_private *cs3= 5l56) if (ret !=3D 0) goto err; =20 + ret =3D cs35l56_process_xu_properties(cs35l56); + if (ret) + goto err; + ret =3D cs35l56_dsp_init(cs35l56); if (ret < 0) { dev_err_probe(cs35l56->base.dev, ret, "DSP init failed\n"); diff --git a/sound/soc/codecs/cs35l56.h b/sound/soc/codecs/cs35l56.h index 7187885a13c1..691f857d0bd8 100644 --- a/sound/soc/codecs/cs35l56.h +++ b/sound/soc/codecs/cs35l56.h @@ -76,6 +76,8 @@ void cs35l56_remove(struct cs35l56_private *cs35l56); =20 #if IS_ENABLED(CONFIG_KUNIT) int cs35l56_set_fw_suffix(struct cs35l56_private *cs35l56); +int cs35l56_set_fw_name(struct snd_soc_component *component); +int cs35l56_process_xu_properties(struct cs35l56_private *cs35l56); #endif =20 #endif /* ifndef CS35L56_H */ --=20 2.47.3 From nobody Sat Feb 7 15:40:02 2026 Received: from mx0b-001ae601.pphosted.com (mx0a-001ae601.pphosted.com [67.231.149.25]) (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 9AEAC439014; Thu, 5 Feb 2026 16:49:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=67.231.149.25 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770310144; cv=fail; b=IPE1U6z11+3e2waKu9jF7Sb6INCZL4H1SxCxYXx6kWwZ3YnbQkk5o67I5utWX/krx6JgSlZotkoFnWJVB3AZY1sptAYs8Qr6xReSvjujgS92yas47H7/gkvDr/uAihsDKakz8L0z4oMlc9sgosf8Iw4Yan7X0yPQIHGFkZkHox0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770310144; c=relaxed/simple; bh=0ouQImyezvRKQoUay1ger2WZIsdkQmDW5VY9oWbnrQo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=N/MuNV6cfAmt9WVmF4iT5vAyFGDub+XZjjocu+xRoQ3iT1nXg83DXVfM9Bgj3SNUSnuM0GKxvdZ9PMH4zmJ4HYz9dExMsmNq2uzHlBuj1EmU/ZAIefn6Kd0ajsQKzcnB+bW7lYt4qzzft/Tgv1+jBDh/GO8KpQJflWtM9Q6kffI= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensource.cirrus.com; spf=pass smtp.mailfrom=opensource.cirrus.com; dkim=pass (2048-bit key) header.d=cirrus.com header.i=@cirrus.com header.b=DUW9n4ha; dkim=pass (1024-bit key) header.d=cirrus4.onmicrosoft.com header.i=@cirrus4.onmicrosoft.com header.b=0Eo5CDJE; arc=fail smtp.client-ip=67.231.149.25 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensource.cirrus.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensource.cirrus.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cirrus.com header.i=@cirrus.com header.b="DUW9n4ha"; dkim=pass (1024-bit key) header.d=cirrus4.onmicrosoft.com header.i=@cirrus4.onmicrosoft.com header.b="0Eo5CDJE" Received: from pps.filterd (m0077473.ppops.net [127.0.0.1]) by mx0a-001ae601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6155hIa4644219; Thu, 5 Feb 2026 10:48:47 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s= PODMain02222019; bh=G/gA8wwSHth6XSjEVD+/rrDkGPLlF5GtBRpUMvO8jDA=; b= DUW9n4hauuJnA3nKMtEYWbbeUdOq3Y7Uvov2nWOtRQdNZgMz8HHiCcko/+KxX/Md 9ojIGmQya1QYtrcfssWDt4n0RUf3ZldPr5jw0Z7C23JGJFE95QDbgX8hGRiueelK XdsekfZG0R/ag2OFywiKzM6rHeahjY2J/sNy+62Vz3f5L2FZcAF6OIavhJOsnmUv oUZQQn/j2uw2wa/f4g0yhpeOeM54LyKPAaqXX5qnIP2P87IU2UYQNohewI59ljIj KXD6FVeJACUoXsNmjx/P0bhCpUdsSsHJtLNcKbyCgd/fia5xIC6VWvNlFi9MuRDY nQzwVh9yIE4iL3pefYXJ0w== Received: from sa9pr02cu001.outbound.protection.outlook.com (mail-southcentralusazon11023131.outbound.protection.outlook.com [40.93.196.131]) by mx0a-001ae601.pphosted.com (PPS) with ESMTPS id 4c1g12x7vu-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 05 Feb 2026 10:48:46 -0600 (CST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=zTPxVWhgRgBPMkwPTmCGgnAQ+4AyZbMrrLs62+vH/F2Qevsww4dUYt6FNzrxDELil2zlQC4lw93rfMZat9ofihACdYdzRQrfWXdu7Rsrh12Kdty7V+Avxs2ieuqxas8aYV6qS30zG8OrisMiFUSIKNWbOE8/rD7Jbc5FlcdrT+flLWRvOhD7MuJcBP0xlcXFdP0q01JvlNcQJ+tBvygEZso23maFadizk5eUTognuhfUHmLMD7OPiY+NGQBBQQEpF4jkNjzyEP05FWe+UVMo6kwwUkA4x/mYNuj/jbCzRHX7ULi3iqKvYo91ETYv4OtSJtm2n37J3TtghAeFsaLb+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=G/gA8wwSHth6XSjEVD+/rrDkGPLlF5GtBRpUMvO8jDA=; b=HeITJDYjSmbziGBjd3HWBi4bBq/XHaekgQJmboXtjVd9Fl4Ul0S3tmsSREz+X30+F0jxaVbR0wtcfwuz5HTl6sI8TnBfbBndC+khUWGTdAJAbkcyw5JEXt9Y02Tf3yhK1kMhMmk9fUd6u1jHSCgk0iYhzDBn6EUy7uk5eYh535DOJJALXq2eTu67D6rwckDXunBp+lA0R4267yp/zy8r3m8kdZmtWqYVTorrAofYwGiH5RqRtnldXvWVuy3CzQpBFftAcn0E8PaaJKKZC6R5Uk2gwMtlsL5omyJaOcRysiyboGwhqHMQac2AzgWwazBSNsxN8UtElsRNhiYim6LdlA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is 84.19.233.75) smtp.rcpttodomain=cirrus.com smtp.mailfrom=opensource.cirrus.com; dmarc=fail (p=reject sp=reject pct=100) action=oreject header.from=opensource.cirrus.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus4.onmicrosoft.com; s=selector2-cirrus4-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=G/gA8wwSHth6XSjEVD+/rrDkGPLlF5GtBRpUMvO8jDA=; b=0Eo5CDJE5VcA3JQEHwxUvZitEaPaCB7F+d0nmqvvRcYFNRnOYYMtP3xcijun7WSW8EUQ2qM75wZLhGiWXP0noKMGs3fPoQqg8snZh7ZALtjmsf8leAJiF/eh5eQWsHuI3PaTrQweHu8Qitf6gBq3xuZdskq8vHx3Y7JTR9W/ALM= Received: from SJ0PR03CA0064.namprd03.prod.outlook.com (2603:10b6:a03:331::9) by SJ4PPFEFEBC5103.namprd19.prod.outlook.com (2603:10b6:a0f:fc02::a5f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9587.15; Thu, 5 Feb 2026 16:48:40 +0000 Received: from SJ1PEPF00002319.namprd03.prod.outlook.com (2603:10b6:a03:331:cafe::db) by SJ0PR03CA0064.outlook.office365.com (2603:10b6:a03:331::9) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.15 via Frontend Transport; Thu, 5 Feb 2026 16:48:40 +0000 X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 84.19.233.75) smtp.mailfrom=opensource.cirrus.com; dkim=none (message not signed) header.d=none;dmarc=fail action=oreject header.from=opensource.cirrus.com; Received-SPF: Fail (protection.outlook.com: domain of opensource.cirrus.com does not designate 84.19.233.75 as permitted sender) receiver=protection.outlook.com; client-ip=84.19.233.75; helo=edirelay1.ad.cirrus.com; Received: from edirelay1.ad.cirrus.com (84.19.233.75) by SJ1PEPF00002319.mail.protection.outlook.com (10.167.242.229) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.10 via Frontend Transport; Thu, 5 Feb 2026 16:48:40 +0000 Received: from ediswmail9.ad.cirrus.com (ediswmail9.ad.cirrus.com [198.61.86.93]) by edirelay1.ad.cirrus.com (Postfix) with ESMTPS id B374E40654F; Thu, 5 Feb 2026 16:48:38 +0000 (UTC) Received: from ediswws06.ad.cirrus.com (ediswws06.ad.cirrus.com [198.90.208.24]) by ediswmail9.ad.cirrus.com (Postfix) with ESMTPSA id 9948582026B; Thu, 5 Feb 2026 16:48:38 +0000 (UTC) From: Richard Fitzgerald To: broonie@kernel.org Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, patches@opensource.cirrus.com Subject: [PATCH 2/3] ASoC: cs35l56-shared: KUnit tests for onchip speaker ID gpios Date: Thu, 5 Feb 2026 16:48:37 +0000 Message-ID: <20260205164838.1611295-3-rf@opensource.cirrus.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260205164838.1611295-1-rf@opensource.cirrus.com> References: <20260205164838.1611295-1-rf@opensource.cirrus.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ1PEPF00002319:EE_|SJ4PPFEFEBC5103:EE_ X-MS-Office365-Filtering-Correlation-Id: 8d9aa4fd-83af-4002-53a1-08de64d66a82 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|61400799027|36860700013|376014|54012099003; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?aLu+UDa8Lnc1vUascwG/e9ahvzgfm/mTPErtHgVLMQnylbMqyh0SFLMPz8U9?= =?us-ascii?Q?MRdpJJCKtV9RQZDIb0ag3IdmJWI/9XXOWugnjnUqR7vy6010pzIOD7R3mhvu?= =?us-ascii?Q?9/ohybZxD50+ggudk/Erke6cHBipo1PufnfIAS8yzzqbIKPeif4oj/8VwNzr?= =?us-ascii?Q?Agr5ZEvWda55nOCeCCGjVd3KiKyY2f4iU6zsdlFbjv3AaXxXyhhezwVSpcvs?= =?us-ascii?Q?JnXcWRdgTBIwHEQBm1O3UtzdXbs24jWRjqWrLSunOgw0BogNTSKENRvqsLN+?= =?us-ascii?Q?RNM2JhhebIKx5bXQ4AOEeOfs5apRCJMoqvFwAD5zc5Y5UuU1X7h5ppMEsnCS?= =?us-ascii?Q?CpXnfDeJ0M9gj5UUnX7gUCct/9rezqmHbD7IVW5C4vnYhX8IWbc75hVx/EeN?= =?us-ascii?Q?KVJriWCeLSIZl20FhBm/XAdBWb2eDpcyqKI852iIbmWpmh7MBGt/fRfhmCCN?= =?us-ascii?Q?mV1kTYuvImUGBpHt9p1OkObLPAtL/+Rp0iZOrj/OitIUhd1JOAy5awYidpTF?= =?us-ascii?Q?UtuWabHKG+2A8U5dalHp3yyHsqKJQ/zvOGq/kDw0d1RhzohZGNyIj3YLYG76?= =?us-ascii?Q?YFynIgVQGqJpv1kj0/0YKJZlXfGLC42G/zwjGDlQHs19k5ozJaMqMpxEl9t+?= =?us-ascii?Q?cVU1ui2IFspa0z5iBEPcWI0d+m3rUy3Sk2UrAZSrRL30bcqUCPtSmtJOLQT/?= =?us-ascii?Q?a+pcXULYxVxEKCFD0S1IS/k9YivaTzjfywoQIGk8bJxzNNjl+LKtUFr3irTp?= =?us-ascii?Q?rCzaSM7Qv0iUFz3H6ctXKI8yzxKww4oR7//qfLJUjN9v8ZpzeYzO3CAWklCK?= =?us-ascii?Q?LZlF6tFnZol8ahxjY8TmZc8Zij+aXe7b98pg/7YC4qeTy2FXsEmdt3zCgTs2?= =?us-ascii?Q?KsaOs2Mp3KfZYQSYTsL8m3KgAkQ+zmC4hf9nZ0R4KtbLr2bT4sDcjFlruAAk?= =?us-ascii?Q?2BmnLPfupn2B9k8aWPhVRumLRwjOj+EqSyLqbpfeqxHz6j/E2bU41pJpiYdW?= =?us-ascii?Q?vQTgTDzvG2q33OwO90SH7W3j0SrlyVvazpOe1SZvBDCgo+SFsmATokTOgKYE?= =?us-ascii?Q?5s/oubx5qrITU/hNVTW7G9H9xdqGP8cNtAy2E/KLc5VzpGHRZZ/zz6C5CgzQ?= =?us-ascii?Q?k/4oQnnE0cr3u38Tc55WYogqawbpj6SCe9KfNU/ySSqB2Qv70QduklJZlHf4?= =?us-ascii?Q?vYtm0uKTvMGxYZxVIcmVS6yJVXwwiosM+x3+O1esbOLCCbydrfuhd522cL4p?= =?us-ascii?Q?xKm0HHaq8xTEzEFbotNGpOoYKuBOHw0ajJNddsDf/9CzjYUF2rGy106Ar/26?= =?us-ascii?Q?R977bwvsPngQQxfBCn4LL2fZbI4FFBi9FLevS/ZUX7KVOlX3NkFPDk9KKFUw?= =?us-ascii?Q?1lV9rCKyudQNwMDtEcMPkyis07d5CNCU8g6sVZLDH1uZ9gFjN9R/fTRIXSas?= =?us-ascii?Q?ha9DvsOZcrQda76CnJTQdrsQDvdzenhzY7Y2iMND4JaHo1YNFqp4pK/Mridb?= =?us-ascii?Q?znAKMjttgKg4vaOK8m4g3q+oBYtbvFGA8h11azR+WapDskXVkVZ9Tj6pBCuO?= =?us-ascii?Q?Ih+s4YL780TprA63Alu1jRWb0mwFQN51fiwkuTPXDvFcytn+65IhTavXq5Jo?= =?us-ascii?Q?AZwZZuXb5gyPCLN5/+Ww4eisfzhRan+X2d8dm0WzkJHyn9y1gab0B94TrtPN?= =?us-ascii?Q?U6PXyw=3D=3D?= X-Forefront-Antispam-Report: CIP:84.19.233.75;CTRY:GB;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:edirelay1.ad.cirrus.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(61400799027)(36860700013)(376014)(54012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: AmG5626VAzMnvyd6Gcrq1wjbJRbPsoP5EkFYRV9dq9v5HEZ6Ek0f7P2PILq7csERULzjeVK8v+Yk4nhO6qg4cQRwEPwfz4dNtEhVp77ZcQNHFWE8aLX7qkQH01n+HFvJI5dyUlPrPjFkvPl5ETggSrMOGqolwbEcSUhDFHeS8v/I9tI19MHBuo8GKCwL/W9/m5oldXVa9sBIuI5AmK/sVIQumDPd/LtRf6N+ezlCoHzAW8OhTM8xH04Ea2olAICyYLkSJiA7xd12oyc7s5IGcodOYmawn9HdkwVTZRI84GdZ2iH47fx7aoDw/T0uQY8eZ5/q/CklWfw0aiDagR2/oxMGn8kdCyhofEUonRVk2iMPNVA2FLl9sKckVBRFVcjSkfsKx5TLkTtaJb4bj74UDJkfS/dbjL2woIqJY7gCEF4e8tH6FBr+t7oVEzA65+u6 X-OriginatorOrg: opensource.cirrus.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Feb 2026 16:48:40.1080 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 8d9aa4fd-83af-4002-53a1-08de64d66a82 X-MS-Exchange-CrossTenant-Id: bec09025-e5bc-40d1-a355-8e955c307de8 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=bec09025-e5bc-40d1-a355-8e955c307de8;Ip=[84.19.233.75];Helo=[edirelay1.ad.cirrus.com] X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: TreatMessagesAsInternal-SJ1PEPF00002319.namprd03.prod.outlook.com X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ4PPFEFEBC5103 X-Proofpoint-GUID: 8nCORmipqMiuvPG7M5RqSSqbWLpH9ghZ X-Authority-Analysis: v=2.4 cv=Mdthep/f c=1 sm=1 tr=0 ts=6984c9ee cx=c_pps a=BJVTd8GDi1tipuH6XGV+IA==:117 a=h1hSm8JtM9GN1ddwPAif2w==:17 a=6eWqkTHjU83fiwn7nKZWdM+Sl24=:19 a=z/mQ4Ysz8XfWz/Q5cLBRGdckG28=:19 a=HzLeVaNsDn8A:10 a=s63m1ICgrNkA:10 a=RWc_ulEos4gA:10 a=VkNPw1HP01LnGYTKEx00:22 a=w1d2syhTAAAA:8 a=hg5lxr8L_Hq_N_W_to4A:9 X-Proofpoint-ORIG-GUID: 8nCORmipqMiuvPG7M5RqSSqbWLpH9ghZ X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjA1MDEyNyBTYWx0ZWRfX7TpvZtVbl4ks JisvR4D2d2wWFzg+h4745dIBITKHLt+aFRwnwgsMmJ2Yq3xgkReX6vf/UGra5yttPknsgej5o6m MYSvQIHhBcAdhR7eWV5LHEcbeiOSe4O3IBcErSQIe7vHHmDgBCz74maYckkVDghLWNeW5jX4hfl AG4tm72LpgXs7Puhn83cAVnoCB/alay4bJ/VVygejDG6DRIlXRAqa/1ralfFKOdfTYxDeSoFoFZ RmScaMkO2/+Or2VRXXSkg+KGgrRAdV9fxSijKTYiN7sNuZ4EcB7cyAgwscCidaPbxLml4FegUBJ JFefI28dKyE9xHxSAhW7aiga/O+FFDjLdBT5XZOEisvnDcdU+GnyO8I0daZVipx05/JTZtsN6NN eW2RNTNAtjuhcadWecjaGNQvuaW4pPmXQy70sOQ6AMjCWsEiHeIWstQQok7Sjz4oKeYzkQLfHOf 27K6X0OfJdBGLyKey5Q== X-Proofpoint-Spam-Reason: safe Content-Type: text/plain; charset="utf-8" Add KUnit testing of: cs35l56_check_and_save_onchip_spkid_gpios() cs35l56_configure_onchip_spkid_pads() cs35l56_read_onchip_spkid() The test consists of: - A mock regmap that simulates the pad and pin config registers. - Parameterization of the pin list, pulls list, a simulated value for each pin and the speaker ID value that this should produce. - A self-test of the simulated pin and GPIO registers. - A test that the value returned by cs35l56_read_onchip_spkid() is correct. - A test that the pin pull-up/down are set correctly by cs35l56_configure_onchip_spkid_pads() - A test that cs35l56_configure_onchip_spkid_pads() and cs35l56_read_onchip_spkid(0 return the expected values if cs35l56_base->num_onchip_spkid_gpios =3D=3D 0. - A test that cs35l56_check_and_save_onchip_spkid_gpios() saves the configuration. - A test that cs35l56_check_and_save_onchip_spkid_gpios() rejects illegal GPIO numbers. - A test that cs35l56_check_and_save_onchip_spkid_gpios() rejects illegal pull types. Signed-off-by: Richard Fitzgerald --- sound/soc/codecs/Kconfig | 14 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs35l56-shared-test.c | 680 +++++++++++++++++++++++++ sound/soc/codecs/cs35l56-shared.c | 5 + 4 files changed, 701 insertions(+) create mode 100644 sound/soc/codecs/cs35l56-shared-test.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e78ac302da15..adb3fb923be3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -936,6 +936,20 @@ config SND_SOC_CS35L56_TEST help This builds KUnit tests for the Cirrus Logic cs35l56 codec driver. + + For more information on KUnit and unit tests in general, + please refer to the KUnit documentation in + Documentation/dev-tools/kunit/. + If in doubt, say "N". + +config SND_SOC_CS35L56_SHARED_TEST + tristate "KUnit test for Cirrus Logic cs35l56-shared" if !KUNIT_ALL_TESTS + depends on SND_SOC_CS35L56_SHARED && KUNIT + default KUNIT_ALL_TESTS + help + This builds KUnit tests for the Cirrus Logic cs35l56-shared + module. + For more information on KUnit and unit tests in general, please refer to the KUnit documentation in Documentation/dev-tools/kunit/. diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index c9e3b813653d..3ddee5298721 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -77,6 +77,7 @@ snd-soc-cs35l45-spi-y :=3D cs35l45-spi.o snd-soc-cs35l45-i2c-y :=3D cs35l45-i2c.o snd-soc-cs35l56-y :=3D cs35l56.o snd-soc-cs35l56-shared-y :=3D cs35l56-shared.o +snd-soc-cs35l56-shared-test-y :=3D cs35l56-shared-test.o snd-soc-cs35l56-i2c-y :=3D cs35l56-i2c.o snd-soc-cs35l56-spi-y :=3D cs35l56-spi.o snd-soc-cs35l56-sdw-y :=3D cs35l56-sdw.o @@ -512,6 +513,7 @@ obj-$(CONFIG_SND_SOC_CS35L45_SPI) +=3D snd-soc-cs35l45-= spi.o obj-$(CONFIG_SND_SOC_CS35L45_I2C) +=3D snd-soc-cs35l45-i2c.o obj-$(CONFIG_SND_SOC_CS35L56) +=3D snd-soc-cs35l56.o obj-$(CONFIG_SND_SOC_CS35L56_SHARED) +=3D snd-soc-cs35l56-shared.o +obj-$(CONFIG_SND_SOC_CS35L56_SHARED_TEST) +=3D snd-soc-cs35l56-shared-test= .o obj-$(CONFIG_SND_SOC_CS35L56_I2C) +=3D snd-soc-cs35l56-i2c.o obj-$(CONFIG_SND_SOC_CS35L56_SPI) +=3D snd-soc-cs35l56-spi.o obj-$(CONFIG_SND_SOC_CS35L56_SDW) +=3D snd-soc-cs35l56-sdw.o diff --git a/sound/soc/codecs/cs35l56-shared-test.c b/sound/soc/codecs/cs35= l56-shared-test.c new file mode 100644 index 000000000000..94db02aef7dc --- /dev/null +++ b/sound/soc/codecs/cs35l56-shared-test.c @@ -0,0 +1,680 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// KUnit test for the Cirrus Logic cs35l56-shared module. +// +// Copyright (C) 2026 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct cs35l56_shared_test_priv { + struct kunit *test; + struct faux_device *amp_dev; + struct regmap *registers; + struct cs35l56_base *cs35l56_base; + u8 applied_pad_pull_state[CS35L56_MAX_GPIO]; +}; + +struct cs35l56_shared_test_param { + int spkid_gpios[4]; + int spkid_pulls[4]; + unsigned long gpio_status; + int spkid; +}; + +KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destr= oy, + struct faux_device *) + +KUNIT_DEFINE_ACTION_WRAPPER(regmap_exit_wrapper, regmap_exit, struct regma= p *) + +static const struct regmap_config cs35l56_shared_test_mock_registers_regma= p =3D { + .reg_bits =3D 32, + .val_bits =3D 32, + .reg_stride =3D 4, + .max_register =3D CS35L56_DSP1_PMEM_5114, + .cache_type =3D REGCACHE_MAPLE, +}; + +static const struct regmap_bus cs35l56_shared_test_mock_registers_regmap_b= us =3D { + /* No handlers because it is always in cache-only */ +}; + +static unsigned int cs35l56_shared_test_read_gpio_status(struct cs35l56_sh= ared_test_priv *priv) +{ + const struct cs35l56_shared_test_param *param =3D priv->test->param_value; + unsigned int reg_offs, pad_cfg, val; + unsigned int status =3D 0; + unsigned int mask =3D 1; + + for (reg_offs =3D 0; reg_offs < CS35L56_MAX_GPIO * sizeof(u32); reg_offs = +=3D sizeof(u32)) { + regmap_read(priv->registers, CS35L56_SYNC_GPIO1_CFG + reg_offs, &pad_cfg= ); + regmap_read(priv->registers, CS35L56_GPIO1_CTRL1 + reg_offs, &val); + + /* Only read a value if set as an input pin and as a GPIO */ + val &=3D (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_MASK); + if ((pad_cfg & CS35L56_PAD_GPIO_IE) && + (val =3D=3D (CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO))) + status |=3D (param->gpio_status & mask); + + mask <<=3D 1; + } + + return status; +} + +static int cs35l56_shared_test_updt_gpio_pres(struct cs35l56_shared_test_p= riv *priv, + unsigned int reg, unsigned int val) +{ + int i, ret; + + ret =3D regmap_write(priv->registers, reg, val); + if (ret) + return ret; + + if (val & CS35L56_UPDT_GPIO_PRES) { + /* Simulate transferring register state to internal latches */ + for (i =3D 0; i < ARRAY_SIZE(priv->applied_pad_pull_state); i++) { + reg =3D CS35L56_SYNC_GPIO1_CFG + (i * sizeof(u32)); + regmap_read(priv->registers, reg, &val); + val =3D FIELD_GET(CS35L56_PAD_GPIO_PULL_MASK, val); + priv->applied_pad_pull_state[i] =3D val; + } + } + + return 0; +} + +static int cs35l56_shared_test_reg_read(void *context, unsigned int reg, u= nsigned int *val) +{ + struct cs35l56_shared_test_priv *priv =3D context; + + switch (reg) { + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: + case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1: + return regmap_read(priv->registers, reg, val); + case CS35L56_UPDATE_REGS: + *val =3D 0; + return 0; + case CS35L56_GPIO_STATUS1: + *val =3D cs35l56_shared_test_read_gpio_status(priv); + return 0; + default: + kunit_fail_current_test("Bad regmap read address %#x\n", reg); + return -EINVAL; + } +} + +static int cs35l56_shared_test_reg_write(void *context, unsigned int reg, = unsigned int val) +{ + struct cs35l56_shared_test_priv *priv =3D context; + + switch (reg) { + case CS35L56_UPDATE_REGS: + return cs35l56_shared_test_updt_gpio_pres(priv, reg, val); + case CS35L56_SYNC_GPIO1_CFG ... CS35L56_ASP2_DIO_GPIO13_CFG: + case CS35L56_GPIO1_CTRL1 ... CS35L56_GPIO13_CTRL1: + return regmap_write(priv->registers, reg, val); + default: + kunit_fail_current_test("Bad regmap write address %#x\n", reg); + return -EINVAL; + } +} + +static const struct regmap_bus cs35l56_shared_test_regmap_bus =3D { + .reg_read =3D cs35l56_shared_test_reg_read, + .reg_write =3D cs35l56_shared_test_reg_write, + .reg_format_endian_default =3D REGMAP_ENDIAN_LITTLE, + .val_format_endian_default =3D REGMAP_ENDIAN_LITTLE, +}; + +/* + * Self-test that the mock GPIO registers obey the configuration bits. + * Other tests rely on the mocked registers only returning a GPIO state + * if the pin is correctly set as a GPIO input. + */ +static void cs35l56_shared_test_mock_gpio_status_selftest(struct kunit *te= st) +{ + const struct cs35l56_shared_test_param *param =3D test->param_value; + struct cs35l56_shared_test_priv *priv =3D test->priv; + struct cs35l56_base *cs35l56_base =3D priv->cs35l56_base; + unsigned int reg, val; + + KUNIT_ASSERT_NOT_NULL(test, param); + + /* Set all pins non-GPIO and output. Mock GPIO_STATUS should read 0 */ + for (reg =3D CS35L56_GPIO1_CTRL1; reg <=3D CS35L56_GPIO13_CTRL1; reg +=3D= sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); + + /* Set all pads as inputs */ + for (reg =3D CS35L56_SYNC_GPIO1_CFG; reg <=3D CS35L56_ASP2_DIO_GPIO13_CFG= ; reg +=3D sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_PAD_= GPIO_IE)); + + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_S= TATUS1, &val)); + KUNIT_EXPECT_EQ(test, val, 0); + + /* Set all pins as GPIO outputs. Mock GPIO_STATUS should read 0 */ + for (reg =3D CS35L56_GPIO1_CTRL1; reg <=3D CS35L56_GPIO13_CTRL1; reg +=3D= sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO= _FN_GPIO)); + + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_S= TATUS1, &val)); + KUNIT_EXPECT_EQ(test, val, 0); + + /* Set all pins as non-GPIO inputs. Mock GPIO_STATUS should read 0 */ + for (reg =3D CS35L56_GPIO1_CTRL1; reg <=3D CS35L56_GPIO13_CTRL1; reg +=3D= sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, CS35L56_GPIO= _DIR_MASK)); + + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_S= TATUS1, &val)); + KUNIT_EXPECT_EQ(test, val, 0); + + /* Set all pins as GPIO inputs. Mock GPIO_STATUS should match param->gpio= _status */ + for (reg =3D CS35L56_GPIO1_CTRL1; reg <=3D CS35L56_GPIO13_CTRL1; reg +=3D= sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, + regmap_write(priv->registers, reg, + CS35L56_GPIO_DIR_MASK | CS35L56_GPIO_FN_GPIO)); + + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_S= TATUS1, &val)); + KUNIT_EXPECT_EQ(test, val, param->gpio_status); + + /* Set all pads as outputs. Mock GPIO_STATUS should read 0 */ + for (reg =3D CS35L56_SYNC_GPIO1_CFG; reg <=3D CS35L56_ASP2_DIO_GPIO13_CFG= ; reg +=3D sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); + + KUNIT_ASSERT_EQ(test, 0, regmap_read(cs35l56_base->regmap, CS35L56_GPIO_S= TATUS1, &val)); + KUNIT_EXPECT_EQ(test, val, 0); +} + +/* Test that the listed chip pins are assembled into a speaker ID integer.= */ +static void cs35l56_shared_test_get_onchip_speaker_id(struct kunit *test) +{ + const struct cs35l56_shared_test_param *param =3D test->param_value; + struct cs35l56_shared_test_priv *priv =3D test->priv; + struct cs35l56_base *cs35l56_base =3D priv->cs35l56_base; + unsigned int i, reg; + + /* Set all pins non-GPIO and output */ + for (reg =3D CS35L56_GPIO1_CTRL1; reg <=3D CS35L56_GPIO13_CTRL1; reg +=3D= sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); + + for (reg =3D CS35L56_SYNC_GPIO1_CFG; reg <=3D CS35L56_ASP2_DIO_GPIO13_CFG= ; reg +=3D sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); + + /* Init GPIO array */ + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { + if (param->spkid_gpios[i] < 0) + break; + + cs35l56_base->onchip_spkid_gpios[i] =3D param->spkid_gpios[i] - 1; + cs35l56_base->num_onchip_spkid_gpios++; + } + + cs35l56_base->num_onchip_spkid_pulls =3D 0; + + KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), = 0); + KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), param->spk= id); +} + +/* Test that the listed chip pins and the corresponding pads are configure= d correctly. */ +static void cs35l56_shared_test_onchip_speaker_id_pad_config(struct kunit = *test) +{ + const struct cs35l56_shared_test_param *param =3D test->param_value; + struct cs35l56_shared_test_priv *priv =3D test->priv; + struct cs35l56_base *cs35l56_base =3D priv->cs35l56_base; + unsigned int i, reg, val; + + /* Init values in all pin registers */ + for (reg =3D CS35L56_GPIO1_CTRL1; reg <=3D CS35L56_GPIO13_CTRL1; reg +=3D= sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); + + for (reg =3D CS35L56_SYNC_GPIO1_CFG; reg <=3D CS35L56_ASP2_DIO_GPIO13_CFG= ; reg +=3D sizeof(u32)) + KUNIT_ASSERT_EQ(test, 0, regmap_write(priv->registers, reg, 0)); + + /* Init GPIO array */ + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { + if (param->spkid_gpios[i] < 0) + break; + + cs35l56_base->onchip_spkid_gpios[i] =3D param->spkid_gpios[i] - 1; + cs35l56_base->num_onchip_spkid_gpios++; + } + + /* Init pulls array */ + for (i =3D 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { + if (param->spkid_pulls[i] < 0) + break; + + cs35l56_base->onchip_spkid_pulls[i] =3D param->spkid_pulls[i]; + cs35l56_base->num_onchip_spkid_pulls++; + } + + KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), = 0); + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { + if (param->spkid_gpios[i] < 0) + break; + + /* Pad should be an input */ + reg =3D CS35L56_SYNC_GPIO1_CFG + ((param->spkid_gpios[i] - 1) * sizeof(u= 32)); + KUNIT_EXPECT_EQ(test, regmap_read(priv->registers, reg, &val), 0); + KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_IE, CS35L56_PAD_GPIO_IE); + + /* Specified pulls should be set, others should be none */ + if (i < cs35l56_base->num_onchip_spkid_pulls) { + KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK, + FIELD_PREP(CS35L56_PAD_GPIO_PULL_MASK, + param->spkid_pulls[i])); + } else { + KUNIT_EXPECT_EQ(test, val & CS35L56_PAD_GPIO_PULL_MASK, + CS35L56_PAD_PULL_NONE); + } + + /* Pulls for all specfied GPIOs should have been transferred to AO latch= */ + if (i < cs35l56_base->num_onchip_spkid_pulls) { + KUNIT_EXPECT_EQ(test, + priv->applied_pad_pull_state[param->spkid_gpios[i] - 1], + param->spkid_pulls[i]); + } else { + KUNIT_EXPECT_EQ(test, + priv->applied_pad_pull_state[param->spkid_gpios[i] - 1], + CS35L56_PAD_PULL_NONE); + } + } +} + +/* Test that the listed chip pins are stashed correctly. */ +static void cs35l56_shared_test_stash_onchip_spkid_pins(struct kunit *test) +{ + const struct cs35l56_shared_test_param *param =3D test->param_value; + struct cs35l56_shared_test_priv *priv =3D test->priv; + struct cs35l56_base *cs35l56_base =3D priv->cs35l56_base; + u32 gpios[5], pulls[5]; + int i, num_gpios, num_pulls; + + static_assert(ARRAY_SIZE(gpios) >=3D ARRAY_SIZE(param->spkid_gpios)); + static_assert(ARRAY_SIZE(pulls) >=3D ARRAY_SIZE(param->spkid_pulls)); + + num_gpios =3D 0; + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { + if (param->spkid_gpios[i] < 0) + break; + + gpios[i] =3D (u32)param->spkid_gpios[i]; + num_gpios++; + } + + num_pulls =3D 0; + for (i =3D 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { + if (param->spkid_pulls[i] < 0) + break; + + pulls[i] =3D (u32)param->spkid_pulls[i]; + num_pulls++; + } + + cs35l56_base->num_onchip_spkid_gpios =3D 0; + cs35l56_base->num_onchip_spkid_pulls =3D 0; + + KUNIT_ASSERT_LE(test, num_gpios, ARRAY_SIZE(cs35l56_base->onchip_spkid_gp= ios)); + KUNIT_ASSERT_LE(test, num_pulls, ARRAY_SIZE(cs35l56_base->onchip_spkid_pu= lls)); + + KUNIT_EXPECT_EQ(test, + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, + gpios, num_gpios, + pulls, num_pulls), + 0); + + KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_gpios, num_gpios); + KUNIT_EXPECT_EQ(test, cs35l56_base->num_onchip_spkid_pulls, num_pulls); + + /* GPIO numbers are adjusted from 1-based to 0-based */ + for (i =3D 0; i < num_gpios; i++) + KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_gpios[i], gpios[i] - 1); + + for (i =3D 0; i < num_pulls; i++) + KUNIT_EXPECT_EQ(test, cs35l56_base->onchip_spkid_pulls[i], pulls[i]); +} + +/* Test that illegal GPIO numbers are rejected. */ +static void cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid(str= uct kunit *test) +{ + struct cs35l56_shared_test_priv *priv =3D test->priv; + struct cs35l56_base *cs35l56_base =3D priv->cs35l56_base; + u32 gpios[8] =3D { }, pulls[8] =3D { }; + + KUNIT_EXPECT_LE(test, + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, + gpios, 1, + pulls, 0), + 0); + + switch (cs35l56_base->type) { + case 0x54: + case 0x56: + case 0x57: + gpios[0] =3D CS35L56_MAX_GPIO + 1; + break; + case 0x63: + gpios[0] =3D CS35L63_MAX_GPIO + 1; + break; + default: + kunit_fail_current_test("Unsupported type:%#x\n", cs35l56_base->type); + return; + } + KUNIT_EXPECT_LE(test, + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, + gpios, 1, + pulls, 0), + 0); + + gpios[0] =3D 1; + pulls[0] =3D 3; + KUNIT_EXPECT_LE(test, + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, + gpios, 1, + pulls, 1), + 0); + + static_assert(ARRAY_SIZE(gpios) > ARRAY_SIZE(cs35l56_base->onchip_spkid_g= pios)); + static_assert(ARRAY_SIZE(pulls) > ARRAY_SIZE(cs35l56_base->onchip_spkid_p= ulls)); + KUNIT_EXPECT_EQ(test, + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, + gpios, ARRAY_SIZE(gpios), + pulls, 0), + -EOVERFLOW); + KUNIT_EXPECT_EQ(test, + cs35l56_check_and_save_onchip_spkid_gpios(cs35l56_base, + gpios, 1, + pulls, ARRAY_SIZE(pulls)), + -EOVERFLOW); +} + +static void cs35l56_shared_test_onchip_speaker_id_not_defined(struct kunit= *test) +{ + struct cs35l56_shared_test_priv *priv =3D test->priv; + struct cs35l56_base *cs35l56_base =3D priv->cs35l56_base; + + memset(cs35l56_base->onchip_spkid_gpios, 0, sizeof(cs35l56_base->onchip_s= pkid_gpios)); + memset(cs35l56_base->onchip_spkid_pulls, 0, sizeof(cs35l56_base->onchip_s= pkid_pulls)); + cs35l56_base->num_onchip_spkid_gpios =3D 0; + cs35l56_base->num_onchip_spkid_pulls =3D 0; + KUNIT_EXPECT_EQ(test, cs35l56_configure_onchip_spkid_pads(cs35l56_base), = 0); + KUNIT_EXPECT_EQ(test, cs35l56_read_onchip_spkid(cs35l56_base), -ENOENT); +} + +static int cs35l56_shared_test_case_regmap_init(struct kunit *test, + const struct regmap_config *regmap_config) +{ + struct cs35l56_shared_test_priv *priv =3D test->priv; + struct cs35l56_base *cs35l56_base; + + /* + * Create a dummy regmap to simulate a register map by holding the + * values of all simulated registers in the regmap cache. + */ + priv->registers =3D regmap_init(&priv->amp_dev->dev, + &cs35l56_shared_test_mock_registers_regmap_bus, + priv, + &cs35l56_shared_test_mock_registers_regmap); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->registers); + KUNIT_ASSERT_EQ(test, 0, + kunit_add_action_or_reset(test, regmap_exit_wrapper, + priv->registers)); + regcache_cache_only(priv->registers, true); + + /* Create dummy regmap for cs35l56 driver */ + cs35l56_base =3D priv->cs35l56_base; + cs35l56_base->regmap =3D regmap_init(cs35l56_base->dev, + &cs35l56_shared_test_regmap_bus, + priv, + regmap_config); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cs35l56_base->regmap); + KUNIT_ASSERT_EQ(test, 0, + kunit_add_action_or_reset(test, regmap_exit_wrapper, + cs35l56_base->regmap)); + + return 0; +} + +static int cs35l56_shared_test_case_base_init(struct kunit *test, u8 type,= u8 rev, + const struct regmap_config *regmap_config) +{ + struct cs35l56_shared_test_priv *priv; + int ret; + + KUNIT_ASSERT_NOT_NULL(test, cs_amp_test_hooks); + + priv =3D kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + test->priv =3D priv; + priv->test =3D test; + + /* Create dummy amp driver dev */ + priv->amp_dev =3D faux_device_create("cs35l56_shared_test_drv", NULL, NUL= L); + KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev); + KUNIT_ASSERT_EQ(test, 0, + kunit_add_action_or_reset(test, + faux_device_destroy_wrapper, + priv->amp_dev)); + + priv->cs35l56_base =3D kunit_kzalloc(test, sizeof(*priv->cs35l56_base), G= FP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, priv->cs35l56_base); + priv->cs35l56_base->dev =3D &priv->amp_dev->dev; + priv->cs35l56_base->type =3D type; + priv->cs35l56_base->rev =3D rev; + + if (regmap_config) { + ret =3D cs35l56_shared_test_case_regmap_init(test, regmap_config); + if (ret) + return ret; + } + + return 0; +} + +static int cs35l56_shared_test_case_regmap_init_L56_B0_sdw(struct kunit *t= est) +{ + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regm= ap_sdw); +} + +static int cs35l56_shared_test_case_regmap_init_L56_B0_spi(struct kunit *t= est) +{ + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regm= ap_spi); +} + +static int cs35l56_shared_test_case_regmap_init_L56_B0_i2c(struct kunit *t= est) +{ + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb0, &cs35l56_regm= ap_i2c); +} + +static int cs35l56_shared_test_case_regmap_init_L56_B2_sdw(struct kunit *t= est) +{ + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regm= ap_sdw); +} + +static int cs35l56_shared_test_case_regmap_init_L56_B2_spi(struct kunit *t= est) +{ + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regm= ap_spi); +} + +static int cs35l56_shared_test_case_regmap_init_L56_B2_i2c(struct kunit *t= est) +{ + return cs35l56_shared_test_case_base_init(test, 0x56, 0xb2, &cs35l56_regm= ap_i2c); +} + +static int cs35l56_shared_test_case_regmap_init_L63_A1_sdw(struct kunit *t= est) +{ + return cs35l56_shared_test_case_base_init(test, 0x63, 0xa1, &cs35l63_regm= ap_sdw); +} + +static void cs35l56_shared_test_gpio_param_desc(const struct cs35l56_share= d_test_param *param, + char *desc) +{ + DECLARE_SEQ_BUF(gpios, 1 + (2 * ARRAY_SIZE(param->spkid_gpios))); + DECLARE_SEQ_BUF(pulls, 1 + (2 * ARRAY_SIZE(param->spkid_pulls))); + int i; + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { + if (param->spkid_gpios[i] < 0) + break; + + seq_buf_printf(&gpios, "%s%d", (i =3D=3D 0) ? "" : ",", param->spkid_gpi= os[i]); + } + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { + if (param->spkid_pulls[i] < 0) + break; + + seq_buf_printf(&pulls, "%s%d", (i =3D=3D 0) ? "" : ",", param->spkid_pul= ls[i]); + } + + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "gpios:{%s} pulls:{%s} status:%#lx = spkid:%d", + seq_buf_str(&gpios), seq_buf_str(&pulls), param->gpio_status, param->sp= kid); +} + +static const struct cs35l56_shared_test_param cs35l56_shared_test_gpios_se= lftest_cases[] =3D { + { .spkid_gpios =3D { -1 }, .gpio_status =3D GENMASK(12, 0) }, +}; +KUNIT_ARRAY_PARAM(cs35l56_shared_test_gpios_selftest, + cs35l56_shared_test_gpios_selftest_cases, + cs35l56_shared_test_gpio_param_desc); + +static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_s= pkid_cases[] =3D { + { .spkid_gpios =3D { 1, -1 }, .gpio_status =3D 0, .spkid =3D 0 }, + { .spkid_gpios =3D { 1, -1 }, .gpio_status =3D ~BIT(0), .spkid =3D 0 }, + { .spkid_gpios =3D { 1, -1 }, .gpio_status =3D BIT(0), .spkid =3D 1 }, + + { .spkid_gpios =3D { 7, -1 }, .gpio_status =3D 0, .spkid =3D 0 }, + { .spkid_gpios =3D { 7, -1 }, .gpio_status =3D ~BIT(6), .spkid =3D 0 }, + { .spkid_gpios =3D { 7, -1 }, .gpio_status =3D BIT(6), .spkid =3D 1 }, + + { .spkid_gpios =3D { 1, 7, -1 }, .gpio_status =3D 0, .spkid =3D 0 }, + { .spkid_gpios =3D { 1, 7, -1 }, .gpio_status =3D ~(BIT(0) | BIT(6)), .= spkid =3D 0 }, + { .spkid_gpios =3D { 1, 7, -1 }, .gpio_status =3D BIT(6), .spkid =3D 1= }, + { .spkid_gpios =3D { 1, 7, -1 }, .gpio_status =3D BIT(0), .spkid =3D 2= }, + { .spkid_gpios =3D { 1, 7, -1 }, .gpio_status =3D BIT(6) | BIT(0), .spk= id =3D 3 }, + + { .spkid_gpios =3D { 7, 1, -1 }, .gpio_status =3D 0, .spkid =3D 0 }, + { .spkid_gpios =3D { 7, 1, -1 }, .gpio_status =3D ~(BIT(6) | BIT(0)), .= spkid =3D 0 }, + { .spkid_gpios =3D { 7, 1, -1 }, .gpio_status =3D BIT(0), .spkid =3D 1= }, + { .spkid_gpios =3D { 7, 1, -1 }, .gpio_status =3D BIT(6), .spkid =3D 2= }, + { .spkid_gpios =3D { 7, 1, -1 }, .gpio_status =3D BIT(6) | BIT(0), .spk= id =3D 3 }, + + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D 0, .spkid =3D 0= }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D BIT(0), .spkid = =3D 1 }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D BIT(6), .spkid = =3D 2 }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D BIT(6) | BIT(0), = .spkid =3D 3 }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D BIT(2), .spkid = =3D 4 }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D BIT(2) | BIT(0), = .spkid =3D 5 }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D BIT(2) | BIT(6), = .spkid =3D 6 }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .gpio_status =3D BIT(2) | BIT(6) | BI= T(0), .spkid =3D 7 }, +}; +KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid, cs35l56_shared_test_on= chip_spkid_cases, + cs35l56_shared_test_gpio_param_desc); + +static const struct cs35l56_shared_test_param cs35l56_shared_test_onchip_s= pkid_pull_cases[] =3D { + { .spkid_gpios =3D { 1, -1 }, .spkid_pulls =3D { 1, -1 }, }, + { .spkid_gpios =3D { 1, -1 }, .spkid_pulls =3D { 2, -1 }, }, + + { .spkid_gpios =3D { 7, -1 }, .spkid_pulls =3D { 1, -1 }, }, + { .spkid_gpios =3D { 7, -1 }, .spkid_pulls =3D { 2, -1 }, }, + + { .spkid_gpios =3D { 1, 7, -1 }, .spkid_pulls =3D { 1, 1, -1 }, }, + { .spkid_gpios =3D { 1, 7, -1 }, .spkid_pulls =3D { 2, 2, -1 }, }, + + { .spkid_gpios =3D { 7, 1, -1 }, .spkid_pulls =3D { 1, 1, -1 }, }, + { .spkid_gpios =3D { 7, 1, -1 }, .spkid_pulls =3D { 2, 2, -1 }, }, + + { .spkid_gpios =3D { 3, 7, 1, -1 }, .spkid_pulls =3D { 1, 1, 1, -1 }, }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .spkid_pulls =3D { 2, 2, 2, -1 }, }, +}; +KUNIT_ARRAY_PARAM(cs35l56_shared_test_onchip_spkid_pull, + cs35l56_shared_test_onchip_spkid_pull_cases, + cs35l56_shared_test_gpio_param_desc); + +static struct kunit_case cs35l56_shared_test_cases[] =3D { + /* Tests for speaker id */ + KUNIT_CASE_PARAM(cs35l56_shared_test_mock_gpio_status_selftest, + cs35l56_shared_test_gpios_selftest_gen_params), + KUNIT_CASE_PARAM(cs35l56_shared_test_get_onchip_speaker_id, + cs35l56_shared_test_onchip_spkid_gen_params), + KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config, + cs35l56_shared_test_onchip_spkid_gen_params), + KUNIT_CASE_PARAM(cs35l56_shared_test_onchip_speaker_id_pad_config, + cs35l56_shared_test_onchip_spkid_pull_gen_params), + KUNIT_CASE_PARAM(cs35l56_shared_test_stash_onchip_spkid_pins, + cs35l56_shared_test_onchip_spkid_pull_gen_params), + KUNIT_CASE(cs35l56_shared_test_stash_onchip_spkid_pins_reject_invalid), + KUNIT_CASE(cs35l56_shared_test_onchip_speaker_id_not_defined), + { } +}; + +static struct kunit_suite cs35l56_shared_test_suite_L56_B0_sdw =3D { + .name =3D "snd-soc-cs35l56-shared-test_L56_B0_sdw", + .init =3D cs35l56_shared_test_case_regmap_init_L56_B0_sdw, + .test_cases =3D cs35l56_shared_test_cases, +}; + +static struct kunit_suite cs35l56_shared_test_suite_L56_B2_sdw =3D { + .name =3D "snd-soc-cs35l56-shared-test_L56_B2_sdw", + .init =3D cs35l56_shared_test_case_regmap_init_L56_B2_sdw, + .test_cases =3D cs35l56_shared_test_cases, +}; + +static struct kunit_suite cs35l56_shared_test_suite_L63_A1_sdw =3D { + .name =3D "snd-soc-cs35l56-shared-test_L63_A1_sdw", + .init =3D cs35l56_shared_test_case_regmap_init_L63_A1_sdw, + .test_cases =3D cs35l56_shared_test_cases, +}; + +static struct kunit_suite cs35l56_shared_test_suite_L56_B0_spi =3D { + .name =3D "snd-soc-cs35l56-shared-test_L56_B0_spi", + .init =3D cs35l56_shared_test_case_regmap_init_L56_B0_spi, + .test_cases =3D cs35l56_shared_test_cases, +}; + +static struct kunit_suite cs35l56_shared_test_suite_L56_B2_spi =3D { + .name =3D "snd-soc-cs35l56-shared-test_L56_B2_spi", + .init =3D cs35l56_shared_test_case_regmap_init_L56_B2_spi, + .test_cases =3D cs35l56_shared_test_cases, +}; + +static struct kunit_suite cs35l56_shared_test_suite_L56_B0_i2c =3D { + .name =3D "snd-soc-cs35l56-shared-test_L56_B0_i2c", + .init =3D cs35l56_shared_test_case_regmap_init_L56_B0_i2c, + .test_cases =3D cs35l56_shared_test_cases, +}; + +static struct kunit_suite cs35l56_shared_test_suite_L56_B2_i2c =3D { + .name =3D "snd-soc-cs35l56-shared-test_L56_B2_i2c", + .init =3D cs35l56_shared_test_case_regmap_init_L56_B2_i2c, + .test_cases =3D cs35l56_shared_test_cases, +}; + +kunit_test_suites( + &cs35l56_shared_test_suite_L56_B0_sdw, + &cs35l56_shared_test_suite_L56_B2_sdw, + &cs35l56_shared_test_suite_L63_A1_sdw, + + &cs35l56_shared_test_suite_L56_B0_spi, + &cs35l56_shared_test_suite_L56_B2_spi, + + &cs35l56_shared_test_suite_L56_B0_i2c, + &cs35l56_shared_test_suite_L56_B2_i2c, +); + +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); +MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); +MODULE_DESCRIPTION("KUnit test for cs35l56-shared module"); +MODULE_AUTHOR("Richard Fitzgerald "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-s= hared.c index 55c75b9e4172..4707f28bfca2 100644 --- a/sound/soc/codecs/cs35l56-shared.c +++ b/sound/soc/codecs/cs35l56-shared.c @@ -5,6 +5,7 @@ // Copyright (C) 2023 Cirrus Logic, Inc. and // Cirrus Logic International Semiconductor Ltd. =20 +#include #include #include #include @@ -1630,6 +1631,8 @@ int cs35l56_configure_onchip_spkid_pads(struct cs35l5= 6_base *cs35l56_base) int num_gpios, num_pulls; int i, ret; =20 + KUNIT_STATIC_STUB_REDIRECT(cs35l56_configure_onchip_spkid_pads, cs35l56_b= ase); + if (cs35l56_base->num_onchip_spkid_gpios =3D=3D 0) return 0; =20 @@ -1680,6 +1683,8 @@ int cs35l56_read_onchip_spkid(struct cs35l56_base *cs= 35l56_base) int speaker_id =3D 0; int i, ret; =20 + KUNIT_STATIC_STUB_REDIRECT(cs35l56_read_onchip_spkid, cs35l56_base); + if (cs35l56_base->num_onchip_spkid_gpios =3D=3D 0) return -ENOENT; =20 --=20 2.47.3 From nobody Sat Feb 7 15:40:02 2026 Received: from mx0b-001ae601.pphosted.com (mx0b-001ae601.pphosted.com [67.231.152.168]) (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 888B2436372; Thu, 5 Feb 2026 16:49:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=67.231.152.168 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770310143; cv=fail; b=d+UjqfS6OiCRinp7hyYD29ntKuRPuDkakVPP62ivV9w8wqU/3Yd8+xf4VDDsaU4UPhfoKJlAARYS/fcoIv4c8GrBQBhCftcQc+35H1cBrNUn3x37ydekFC7D81H7894YMiGNlJJqDmWkwELg2eNBf5DlepTEupqG2dcRrWVolQc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770310143; c=relaxed/simple; bh=tKdg2hYhrvlFOLZ8f4i++L3VJ2WvdXWEImh1Sa/aNOg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=kRAivKDs8eaEzMqt7ra6P5TSQGLKR/zryHzdXna2CGEU+2r0RlyBkPyRNvZ6WjNQQFwGhdcsi2VpTsP1qVqsOa2tTk5X0i/+xJ6p4bO6DXE6d7gyJT9U15NfPv7J/TUI6ag0tGUkxTcBzvebyONxUfYLVFku6qmbON0VFCKI+b8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensource.cirrus.com; spf=pass smtp.mailfrom=opensource.cirrus.com; dkim=pass (2048-bit key) header.d=cirrus.com header.i=@cirrus.com header.b=ZcbM9u92; dkim=pass (1024-bit key) header.d=cirrus4.onmicrosoft.com header.i=@cirrus4.onmicrosoft.com header.b=P/H4/oxS; arc=fail smtp.client-ip=67.231.152.168 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=opensource.cirrus.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=opensource.cirrus.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=cirrus.com header.i=@cirrus.com header.b="ZcbM9u92"; dkim=pass (1024-bit key) header.d=cirrus4.onmicrosoft.com header.i=@cirrus4.onmicrosoft.com header.b="P/H4/oxS" Received: from pps.filterd (m0077474.ppops.net [127.0.0.1]) by mx0b-001ae601.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6154kNXL3192133; Thu, 5 Feb 2026 10:48:47 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s= PODMain02222019; bh=EaCijJC8t99tGo1GVhMO76ATfy+8n7p2sQn9PXa8GEg=; b= ZcbM9u92bST/5A4WyybJZIr83qaw0c31tYV7OMRBFi1RBQFOfRB2gpNY5b485m3S wIRr6wkS3SPYJmH7cwwOYmFuq6mrhpSEiIvfr7gBYrWt9LhPJyLxVOLZgXFpz52A yzJ0YDSzFbkitsHYOGoIHb/Z7CPATaX2r96gkwtgNVcIAVYKwcUmKhITPZLBizPi Z9Bwee41iNalQb4Cy4UKlM/iOP3p6PNB4TqfjgvZbESmIZI+kbt3/qhVItYXKMZd BK2BMd8h01j2IhfpoAqOaAVwupBQ7xy27kVZDVpRDFBDbVXxMwaJC0WeMb+gBquk vBHUskxXPXHdIgCUnouD1A== Received: from sn4pr0501cu005.outbound.protection.outlook.com (mail-southcentralusazon11021073.outbound.protection.outlook.com [40.93.194.73]) by mx0b-001ae601.pphosted.com (PPS) with ESMTPS id 4c1f1k6bsu-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Thu, 05 Feb 2026 10:48:47 -0600 (CST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=sg9/u6KLwZT5IYG28LslBwKeIc8FvnJStOKlppF/tuaezoGCu5fHEE0G1pb2h5PW5ichqO+ixM2euD/jVcgioYTppdQBUvgbFLHmr3lNM71n1ldN7nQNafryKSAFrsy7ezXhaReUOSBuKXKwq4DaLEFe2FUSaK151ju5TljnVz81UWqwXwLEv/dicwL+mklXzQdrjzfIPqLVm8ADgciB9iqH/5ZA22HLtTMS35T0ikNcT6LF9+DGnGR8MeAm1iW3IFe8UFA9oRTQDObqge7ByJxFk3+5P5xJo52xxXA3LaDpPc/eTTkDRVckzYSCwsU34TxiG7rpcPJFjkSYLWeaug== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=EaCijJC8t99tGo1GVhMO76ATfy+8n7p2sQn9PXa8GEg=; b=Q+l88ca0mVfL4yb18FADhuQo9z/qiTymKIw48xHIbG6yti+YWn6K6570RBJFpR3HxzmJS9nAgIebwvc4h0Z33y4G4q1uEZVs41HgB5etOTlPKLlbCksYNPftEeGYReKuJjk6Uw1NvTiR3SnqF9Q4rewjcudleDZ4O4wG5dy/VOH/Ik6ELUSiRa2U45+O8842zrFZH6crOUorl06Irq4ZZ9fp6VgSiCL2Vb6i/BhOwAzFqzus/r0FAR9kPKPBdKrYtAQJ4B6mYK8IwPsCxQ63JxZjjqHimpk9juw18fhkpgcB5gdZ1j/LPDjiWgDUwnGDmlYY4CWk4x5zgG9/VJ4YNQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=fail (sender ip is 84.19.233.75) smtp.rcpttodomain=cirrus.com smtp.mailfrom=opensource.cirrus.com; dmarc=fail (p=reject sp=reject pct=100) action=oreject header.from=opensource.cirrus.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cirrus4.onmicrosoft.com; s=selector2-cirrus4-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=EaCijJC8t99tGo1GVhMO76ATfy+8n7p2sQn9PXa8GEg=; b=P/H4/oxSVbYo8T3U/m3MSU54Kp/e1I+chLt3SEWHEXFAsGmoTKfA7h97DEzhexH4f1DqCwaNoCr9dNL3jVrsEaKdy1okg+nUMpJc8rU8enqu3GOFMjCugKe9C2p4R9vtjxgy1bg+VbwjIy5qXCm87EGhqxHD1mVEsztTP/5DmZI= Received: from BL0PR05CA0001.namprd05.prod.outlook.com (2603:10b6:208:91::11) by SA3PR19MB9550.namprd19.prod.outlook.com (2603:10b6:806:496::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9587.14; Thu, 5 Feb 2026 16:48:40 +0000 Received: from BL02EPF00021F68.namprd02.prod.outlook.com (2603:10b6:208:91:cafe::7d) by BL0PR05CA0001.outlook.office365.com (2603:10b6:208:91::11) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.15 via Frontend Transport; Thu, 5 Feb 2026 16:48:36 +0000 X-MS-Exchange-Authentication-Results: spf=fail (sender IP is 84.19.233.75) smtp.mailfrom=opensource.cirrus.com; dkim=none (message not signed) header.d=none;dmarc=fail action=oreject header.from=opensource.cirrus.com; Received-SPF: Fail (protection.outlook.com: domain of opensource.cirrus.com does not designate 84.19.233.75 as permitted sender) receiver=protection.outlook.com; client-ip=84.19.233.75; helo=edirelay1.ad.cirrus.com; Received: from edirelay1.ad.cirrus.com (84.19.233.75) by BL02EPF00021F68.mail.protection.outlook.com (10.167.249.4) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9587.10 via Frontend Transport; Thu, 5 Feb 2026 16:48:40 +0000 Received: from ediswmail9.ad.cirrus.com (ediswmail9.ad.cirrus.com [198.61.86.93]) by edirelay1.ad.cirrus.com (Postfix) with ESMTPS id B7A04406554; Thu, 5 Feb 2026 16:48:38 +0000 (UTC) Received: from ediswws06.ad.cirrus.com (ediswws06.ad.cirrus.com [198.90.208.24]) by ediswmail9.ad.cirrus.com (Postfix) with ESMTPSA id 9E77D822542; Thu, 5 Feb 2026 16:48:38 +0000 (UTC) From: Richard Fitzgerald To: broonie@kernel.org Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, patches@opensource.cirrus.com Subject: [PATCH 3/3] ASoC: cs35l56: KUnit tests for parsing and using onchip GPIOs Date: Thu, 5 Feb 2026 16:48:38 +0000 Message-ID: <20260205164838.1611295-4-rf@opensource.cirrus.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260205164838.1611295-1-rf@opensource.cirrus.com> References: <20260205164838.1611295-1-rf@opensource.cirrus.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BL02EPF00021F68:EE_|SA3PR19MB9550:EE_ X-MS-Office365-Filtering-Correlation-Id: 0dac4287-3c98-4aad-2e13-08de64d66a67 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|61400799027|82310400026|36860700013|54012099003; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?W9xaermtmTyze3GOCIvX4g6iH55WwRqrKLyXShOQtgDe8lykocNA1xHXZ+6B?= =?us-ascii?Q?5DR9jk3yD2dZQ/FLEUf9LzUMW0IjP8vJB5OheK6EOOZ1mSwmDs+8S2JSJ7xh?= =?us-ascii?Q?cZnSJjxyumHeo6ZVeZptUG9GJENwG6aIoZss46aNHOfpa2x4RmKMyQebJ/fH?= =?us-ascii?Q?2yAqbBqLj9RyWUjM06dGxDOS5BDaHtieXgQb9J1cRz9cxB+KPEKLjyjWA3w5?= =?us-ascii?Q?fJDzDbGlOxn1TQRdsW6QeZPJsa9uU6v1nueZVaiM5D19StJgm2gbs7YabqIZ?= =?us-ascii?Q?lBCP7ROlAcaXIvtrxfpO37nYPxB2sEjD/5fUuV/sGpGHOJ3TihZy/aqAK4h+?= =?us-ascii?Q?uTGR2NR//PttiTZjkhZiGo3HjQKwi5RQuMYhFNbsM3QcMgCF6HdUSrdk1RpS?= =?us-ascii?Q?jcjMruJekFRajkucDIP3g+a3aHi9bkS7IGOSNoDrLfCzPKWDGGLsDLpXN9Pv?= =?us-ascii?Q?E9XLsWkJouLykwLf5xJsDLuK4UpfmaLgt1dJutERAQoB5h667X+Z5ioOScAy?= =?us-ascii?Q?N/iNmkzESftm4c7oIghd0JGPuMvLEjufGp6R2cmULFKCBCiodDb8OMX2qxCK?= =?us-ascii?Q?Gjzt8mDSguir3jHf+t0j1pvsIKg0Ac8/O18qivibNiwldm0rx+ZFclkgKM9H?= =?us-ascii?Q?C+l6HlVuRbl5VaMeEJgpzL9ir0cjSq01ameXtFaZeruWD2q/+cyprxroI6qW?= =?us-ascii?Q?QkY06gveQCt72L/p8VLHXi3oZDWpK4KkXQ/caU4EhI/47JXVFOrTB+SQYyF6?= =?us-ascii?Q?ru1QnHdc7jAbIba7XSeQcMKMkaCUAQavMD1UBQ+AL8Sm4GEaus4mBXMzLNKy?= =?us-ascii?Q?r8SQcIBxl+a42PY99sbKVyvQApkrW6ng0IrqImZ5UfHXkXkDIBRScCnH9aat?= =?us-ascii?Q?86YrA3aJUUCbsAx1itLpF+pR++pj/wZQr5r1wO1j/3D7LpzdIvXEz8BG+3Cn?= =?us-ascii?Q?NHGxhHG2wUMSiKZsCA7nK9GMSACTR/JqnrufU9v1iqDMZt5fQ3Y+Zxtax9Sl?= =?us-ascii?Q?sqcq1srn48p90pJdhnpoSpP8sXHW5fIjfwgnTZWGjIa9bAHn3W4oJoDO2dZm?= =?us-ascii?Q?TMHZSdMZVA/mWkXZZ29skiy1pWCU/Cw82pePUCmXMq7KaMHg1dhYmcBVZX5l?= =?us-ascii?Q?AFvUdP8GbMeujWgUnHP+W4q7cgHpaEpwnSyCUbCeBGYu2mHEYcTPIr6Q8awG?= =?us-ascii?Q?lqxXLa1PydHJF0Z9ETiHi4yD+WYPaQiOujF4VVfhjBxUeJZVesdirQjGcrBc?= =?us-ascii?Q?i0LBrW0t9gfh6SQF4770mG+4dBMdU+yubSMuPJNifttT3nUIfvClrkRZAYGe?= =?us-ascii?Q?c95l0cs4bNoWGjpYtpYvsG8wAAKa7tLZzpJxJokGVBiRuJR6bHfpOSpkSBzS?= =?us-ascii?Q?DtBV9/4p9U3Rwv5fqGkQ+3fs3pXW3Auh9smybYfTYi9+mX4+6YD76DU7+Yvm?= =?us-ascii?Q?6ydnzsl9w5/egYrooEkVZBQZCu5x8nqwcl3vkKjCpgZYHA906GESwWjTAo1I?= =?us-ascii?Q?wFTdOh0cdmhXmjTXTcEdUVt/AN8l5MlK6smBzl7RjlMWebjmcIzNzAhd415e?= =?us-ascii?Q?R0FypI894vaHCpXnLWrXIkA8qWJNOlmWBYtrr7epcDxsKcy9FiH9izKdddoc?= =?us-ascii?Q?BBilxiGShe4MlOI9AQRMJKv+rZKUWD5nXwryfjPABw9JCTzd0vfTbCi/Qer4?= =?us-ascii?Q?6qiVyQ=3D=3D?= X-Forefront-Antispam-Report: CIP:84.19.233.75;CTRY:GB;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:edirelay1.ad.cirrus.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(376014)(61400799027)(82310400026)(36860700013)(54012099003);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: ZdqH8qW2yko7nXklCsL8mxC2Rtl03nFxt+XtBqREV7OVJYGL13iD0qXBnZcQIvH2VE8C24mrpyecInITGSsutsccJ0qC7PQNJj7saqGjC+j5g4fqC20J3FGaBNWxAQHFyCoxVQTDU4uVaAXt63UGuff8nXowhs4/ihUZdrPoXqHGzK0t5LuSzM6UYp3Kx23ojO4uda6NBnZ0Zb/QzGmwxBFUZPFya7GV1lOb90a8FZvrvK/JugK0l4Z8VhfclBirkPEPJXhpsj4WtpFyeKpqRLYqEsCzUnceNXHPhxX82Qu0xF2zndiUY+kCwYXxzedQLs7FqX+gkoMOk0FxR7C3w6/uLHbXK3313oKg6UwXRXoXbkYtNV5eeDvbwNJ9TsTqtzZ4L0yiTIVuxPRO15tKu5KPJhhtUNpQlvVCsDpB5GAaKJGWZKJdmfMpoSYzZ/nl X-OriginatorOrg: opensource.cirrus.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 05 Feb 2026 16:48:40.2055 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 0dac4287-3c98-4aad-2e13-08de64d66a67 X-MS-Exchange-CrossTenant-Id: bec09025-e5bc-40d1-a355-8e955c307de8 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=bec09025-e5bc-40d1-a355-8e955c307de8;Ip=[84.19.233.75];Helo=[edirelay1.ad.cirrus.com] X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: TreatMessagesAsInternal-BL02EPF00021F68.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA3PR19MB9550 X-Authority-Analysis: v=2.4 cv=d+j4CBjE c=1 sm=1 tr=0 ts=6984c9ef cx=c_pps a=tL1cjTdHg3x6ttwi1NwRWw==:117 a=h1hSm8JtM9GN1ddwPAif2w==:17 a=6eWqkTHjU83fiwn7nKZWdM+Sl24=:19 a=z/mQ4Ysz8XfWz/Q5cLBRGdckG28=:19 a=HzLeVaNsDn8A:10 a=s63m1ICgrNkA:10 a=RWc_ulEos4gA:10 a=VkNPw1HP01LnGYTKEx00:22 a=w1d2syhTAAAA:8 a=xMh_egJBMxf9Zk9P8v0A:9 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwMjA1MDEyNyBTYWx0ZWRfX+6CyZdlA71Zn 1gLJKaxTXN+0Q5aW0JHL01at/GA6c7Au6BBrtVl1/1SyR0yVZC5al/ZtAtBzq1z2TfRgzY0CXz3 rCI+XBzwLVcy994DB7ak3PsZ4AJ6wYFV/1N8lrhsc3EUmsS9YM6ifjdnvRe3LYyhUCSC9SjDdyO fh3flfBeDVV3UoQwHwEIW0ZOJeBVS5OhIYk4Uex5BZiscYwRML5vpb8YIxsoYwaiKKa4vx//K/B FW2Ff19CiG+KkE/LwZSjuZdYTK9frI9ytRqiEFImHNZmc+lDFVncPj7ZZiQq56n2c1RkAoSIQxy ytbb8XFXySMWZxqceeHUMherBvHDm3k8/N/kGI3oTGox1asptPTR5jgF59NUPOaIfoG7emKfLQz zGQ7o4RiGkp3e05vLdOcDSqeLL3hH8nyZfntF5hqIhaHRoTObKjOzbEh2lvnyoqF9no/xqLtm4Z ZvrjuAJ4hYmDm42Njdw== X-Proofpoint-GUID: tQFLLuqQMOnHgKFQ7pbd-yrxpf4rEyxs X-Proofpoint-ORIG-GUID: tQFLLuqQMOnHgKFQ7pbd-yrxpf4rEyxs X-Proofpoint-Spam-Reason: safe Content-Type: text/plain; charset="utf-8" Add KUnit test cases for: - cs35l56_process_xu_properties() which reads the onchip GPIO definitions. - cs35l56_set_fw_name() calls functions to configure and set the GPIOs. - cs35l56_set_fw_name() saves the ID value in cs35l56_priv.speaker_id. - cs35l56_set_fw_name() does not overwrite a speaker ID that was already found some other way. Signed-off-by: Richard Fitzgerald --- sound/soc/codecs/cs35l56-test.c | 273 ++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) diff --git a/sound/soc/codecs/cs35l56-test.c b/sound/soc/codecs/cs35l56-tes= t.c index a7b21660c402..b6c8c08e3ade 100644 --- a/sound/soc/codecs/cs35l56-test.c +++ b/sound/soc/codecs/cs35l56-test.c @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include #include @@ -23,16 +25,46 @@ KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destr= oy, struct faux_device *) =20 +KUNIT_DEFINE_ACTION_WRAPPER(software_node_unregister_node_group_wrapper, + software_node_unregister_node_group, + const struct software_node * const *) + +KUNIT_DEFINE_ACTION_WRAPPER(software_node_unregister_wrapper, + software_node_unregister, + const struct software_node *) + +KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper, + device_remove_software_node, + struct device *) + struct cs35l56_test_priv { struct faux_device *amp_dev; struct cs35l56_private *cs35l56_priv; =20 const char *ssidexv2; + + bool read_onchip_spkid_called; + bool configure_onchip_spkid_pads_called; }; =20 struct cs35l56_test_param { u8 type; u8 rev; + + s32 spkid_gpios[4]; + s32 spkid_pulls[4]; +}; + +static const struct software_node cs35l56_test_dev_sw_node =3D + SOFTWARE_NODE("SWD1", NULL, NULL); + +static const struct software_node cs35l56_test_af01_sw_node =3D + SOFTWARE_NODE("AF01", NULL, &cs35l56_test_dev_sw_node); + +static const struct software_node *cs35l56_test_dev_and_af01_node_group[] = =3D { + &cs35l56_test_dev_sw_node, + &cs35l56_test_af01_sw_node, + NULL }; =20 static const char *cs35l56_test_devm_get_vendor_specific_variant_id_none(s= truct device *dev, @@ -232,6 +264,190 @@ static void cs35l56_test_l56_b0_ssidexv2_ignored_suff= ix_sdw(struct kunit *test) KUNIT_EXPECT_STREQ(test, cs35l56->fallback_fw_suffix, "l1u5"); } =20 +/* + * Test that cs35l56_process_xu_properties() correctly parses the GPIO and + * pull values from properties into the arrays in struct cs35l56_base. + * + * This test creates the node tree: + * + * Node("SWD1") { // top-level device node + * Node("AF01") { + * Node("mipi-sdca-function-expansion-subproperties") { + * property: "01fa-spk-id-gpios-onchip" + * property: 01fa-spk-id-gpios-onchip-pull + * } + * } + * } + * + * Note that in ACPI "mipi-sdca-function-expansion-subproperties" is + * a special _DSD property that points to a Device(EXT0) node but behaves + * as an alias of the EXT0 node. The equivalent in software nodes is to + * create a Node named "mipi-sdca-function-expansion-subproperties" with + * the properties. + * + */ +static void cs35l56_test_parse_xu_onchip_spkid(struct kunit *test) +{ + const struct cs35l56_test_param *param =3D test->param_value; + struct cs35l56_test_priv *priv =3D test->priv; + struct cs35l56_private *cs35l56 =3D priv->cs35l56_priv; + struct software_node *ext0_node; + int num_gpios =3D 0; + int num_pulls =3D 0; + int i; + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++, num_gpios++) { + if (param->spkid_gpios[i] < 0) + break; + } + KUNIT_ASSERT_LE(test, num_gpios, ARRAY_SIZE(cs35l56->base.onchip_spkid_gp= ios)); + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_pulls); i++, num_pulls++) { + if (param->spkid_pulls[i] < 0) + break; + } + KUNIT_ASSERT_LE(test, num_pulls, ARRAY_SIZE(cs35l56->base.onchip_spkid_pu= lls)); + + const struct property_entry ext0_props[] =3D { + PROPERTY_ENTRY_U32_ARRAY_LEN("01fa-spk-id-gpios-onchip", + param->spkid_gpios, num_gpios), + PROPERTY_ENTRY_U32_ARRAY_LEN("01fa-spk-id-gpios-onchip-pull", + param->spkid_pulls, num_pulls), + { } + }; + + KUNIT_ASSERT_EQ(test, + software_node_register_node_group(cs35l56_test_dev_and_af01_node_group), + 0); + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, + software_node_unregister_node_group_wrapper, + cs35l56_test_dev_and_af01_node_group), + 0); + + ext0_node =3D kunit_kzalloc(test, sizeof(*ext0_node), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ext0_node); + *ext0_node =3D SOFTWARE_NODE("mipi-sdca-function-expansion-subproperties", + ext0_props, &cs35l56_test_af01_sw_node); + + KUNIT_ASSERT_EQ(test, software_node_register(ext0_node), 0); + KUNIT_ASSERT_EQ(test, + kunit_add_action_or_reset(test, + software_node_unregister_wrapper, + ext0_node), + 0); + + KUNIT_ASSERT_EQ(test, + device_add_software_node(cs35l56->base.dev, &cs35l56_test_dev_sw_node),= 0); + KUNIT_ASSERT_EQ(test, 0, + kunit_add_action_or_reset(test, + device_remove_software_node_wrapper, + cs35l56->base.dev)); + + KUNIT_EXPECT_EQ(test, cs35l56_process_xu_properties(cs35l56), 0); + + KUNIT_EXPECT_EQ(test, cs35l56->base.num_onchip_spkid_gpios, num_gpios); + KUNIT_EXPECT_EQ(test, cs35l56->base.num_onchip_spkid_pulls, num_pulls); + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { + if (param->spkid_gpios[i] < 0) + break; + + /* + * cs35l56_process_xu_properties() stores the GPIO numbers + * zero-based, which is one less than the value in the property. + */ + KUNIT_EXPECT_EQ_MSG(test, cs35l56->base.onchip_spkid_gpios[i], + param->spkid_gpios[i] - 1, + "i=3D%d", i); + } + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { + if (param->spkid_pulls[i] < 0) + break; + + KUNIT_EXPECT_EQ_MSG(test, cs35l56->base.onchip_spkid_pulls[i], + param->spkid_pulls[i], "i=3D%d", i); + } +} + +static int cs35l56_test_dummy_read_onchip_spkid(struct cs35l56_base *cs35l= 56_base) +{ + struct kunit *test =3D kunit_get_current_test(); + struct cs35l56_test_priv *priv =3D test->priv; + + priv->read_onchip_spkid_called =3D true; + + return 4; +} + +static int cs35l56_test_dummy_configure_onchip_spkid_pads(struct cs35l56_b= ase *cs35l56_base) +{ + struct kunit *test =3D kunit_get_current_test(); + struct cs35l56_test_priv *priv =3D test->priv; + + priv->configure_onchip_spkid_pads_called =3D true; + + return 0; +} + +static void cs35l56_test_set_fw_name_reads_onchip_spkid(struct kunit *test) +{ + struct cs35l56_test_priv *priv =3D test->priv; + struct cs35l56_private *cs35l56 =3D priv->cs35l56_priv; + + /* Provide some on-chip GPIOs for spkid */ + cs35l56->base.onchip_spkid_gpios[0] =3D 1; + cs35l56->base.num_onchip_spkid_gpios =3D 1; + + cs35l56->speaker_id =3D -ENOENT; + + kunit_activate_static_stub(test, + cs35l56_configure_onchip_spkid_pads, + cs35l56_test_dummy_configure_onchip_spkid_pads); + kunit_activate_static_stub(test, + cs35l56_read_onchip_spkid, + cs35l56_test_dummy_read_onchip_spkid); + + priv->configure_onchip_spkid_pads_called =3D false; + priv->read_onchip_spkid_called =3D false; + KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0); + KUNIT_EXPECT_TRUE(test, priv->configure_onchip_spkid_pads_called); + KUNIT_EXPECT_TRUE(test, priv->read_onchip_spkid_called); + KUNIT_EXPECT_EQ(test, cs35l56->speaker_id, + cs35l56_test_dummy_read_onchip_spkid(&cs35l56->base)); +} + +static void cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios(str= uct kunit *test) +{ + struct cs35l56_test_priv *priv =3D test->priv; + struct cs35l56_private *cs35l56 =3D priv->cs35l56_priv; + + /* Provide some on-chip GPIOs for spkid */ + cs35l56->base.onchip_spkid_gpios[0] =3D 1; + cs35l56->base.num_onchip_spkid_gpios =3D 1; + + /* Simulate that the driver already got a spkid from somewhere */ + cs35l56->speaker_id =3D 15; + + KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0); + KUNIT_EXPECT_EQ(test, cs35l56->speaker_id, 15); +} + +static void cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios(= struct kunit *test) +{ + struct cs35l56_test_priv *priv =3D test->priv; + struct cs35l56_private *cs35l56 =3D priv->cs35l56_priv; + + cs35l56->base.num_onchip_spkid_gpios =3D 0; + + /* Simulate that the driver already got a spkid from somewhere */ + cs35l56->speaker_id =3D 15; + + KUNIT_EXPECT_EQ(test, cs35l56_set_fw_name(cs35l56->component), 0); + KUNIT_EXPECT_EQ(test, cs35l56->speaker_id, 15); +} + static int cs35l56_test_case_init_common(struct kunit *test) { struct cs35l56_test_priv *priv; @@ -263,6 +479,7 @@ static int cs35l56_test_case_init_common(struct kunit *= test) cs35l56->component =3D kunit_kzalloc(test, sizeof(*cs35l56->component), G= FP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, cs35l56->component); cs35l56->component->dev =3D cs35l56->base.dev; + snd_soc_component_set_drvdata(cs35l56->component, cs35l56); =20 cs35l56->component->card =3D kunit_kzalloc(test, sizeof(*cs35l56->compone= nt->card), GFP_KERNEL); @@ -299,6 +516,50 @@ static int cs35l56_test_case_init_soundwire(struct kun= it *test) return 0; } =20 +static void cs35l56_test_gpio_param_desc(const struct cs35l56_test_param *= param, char *desc) +{ + DECLARE_SEQ_BUF(gpios, 1 + (2 * ARRAY_SIZE(param->spkid_gpios))); + DECLARE_SEQ_BUF(pulls, 1 + (2 * ARRAY_SIZE(param->spkid_pulls))); + int i; + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_gpios); i++) { + if (param->spkid_gpios[i] < 0) + break; + + seq_buf_printf(&gpios, "%s%d", (i =3D=3D 0) ? "" : ",", param->spkid_gpi= os[i]); + } + + for (i =3D 0; i < ARRAY_SIZE(param->spkid_pulls); i++) { + if (param->spkid_pulls[i] < 0) + break; + + seq_buf_printf(&pulls, "%s%d", (i =3D=3D 0) ? "" : ",", param->spkid_pul= ls[i]); + } + + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "gpios:{%s} pulls:{%s}", + seq_buf_str(&gpios), seq_buf_str(&pulls)); +} + +static const struct cs35l56_test_param cs35l56_test_onchip_spkid_cases[] = =3D { + { .spkid_gpios =3D { 1, -1 }, .spkid_pulls =3D { 1, -1 }, }, + { .spkid_gpios =3D { 1, -1 }, .spkid_pulls =3D { 2, -1 }, }, + + { .spkid_gpios =3D { 7, -1 }, .spkid_pulls =3D { 1, -1 }, }, + { .spkid_gpios =3D { 7, -1 }, .spkid_pulls =3D { 2, -1 }, }, + + { .spkid_gpios =3D { 1, 7, -1 }, .spkid_pulls =3D { 1, 1, -1 }, }, + { .spkid_gpios =3D { 1, 7, -1 }, .spkid_pulls =3D { 2, 2, -1 }, }, + + { .spkid_gpios =3D { 7, 1, -1 }, .spkid_pulls =3D { 1, 1, -1 }, }, + { .spkid_gpios =3D { 7, 1, -1 }, .spkid_pulls =3D { 2, 2, -1 }, }, + + { .spkid_gpios =3D { 3, 7, 1, -1 }, .spkid_pulls =3D { 1, 1, 1, -1 }, }, + { .spkid_gpios =3D { 3, 7, 1, -1 }, .spkid_pulls =3D { 2, 2, 2, -1 }, }, +}; +KUNIT_ARRAY_PARAM(cs35l56_test_onchip_spkid, + cs35l56_test_onchip_spkid_cases, + cs35l56_test_gpio_param_desc); + static void cs35l56_test_type_rev_param_desc(const struct cs35l56_test_par= am *param, char *desc) { @@ -331,6 +592,13 @@ static struct kunit_case cs35l56_test_cases_soundwire[= ] =3D { cs35l56_test_type_rev_ex_b0_gen_params), KUNIT_CASE(cs35l56_test_l56_b0_ssidexv2_ignored_suffix_sdw), =20 + KUNIT_CASE_PARAM(cs35l56_test_parse_xu_onchip_spkid, + cs35l56_test_onchip_spkid_gen_params), + + KUNIT_CASE(cs35l56_test_set_fw_name_reads_onchip_spkid), + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios), + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios), + { } /* terminator */ }; =20 @@ -339,6 +607,10 @@ static struct kunit_case cs35l56_test_cases_not_soundw= ire[] =3D { KUNIT_CASE_PARAM(cs35l56_test_ssidexv2_suffix_i2cspi, cs35l56_test_type_rev_all_gen_params), =20 + KUNIT_CASE(cs35l56_test_set_fw_name_reads_onchip_spkid), + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_with_onchip_gpios), + KUNIT_CASE(cs35l56_test_set_fw_name_preserves_spkid_without_onchip_gpios), + { } /* terminator */ }; =20 @@ -360,6 +632,7 @@ kunit_test_suites( ); =20 MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB"); +MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED"); MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); MODULE_DESCRIPTION("KUnit test for Cirrus Logic cs35l56 codec driver"); MODULE_AUTHOR("Richard Fitzgerald "); --=20 2.47.3