From nobody Wed Apr 1 08:37:52 2026 Received: from CY3PR05CU001.outbound.protection.outlook.com (mail-westcentralusazon11013069.outbound.protection.outlook.com [40.93.201.69]) (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 02D0E35B63D; Wed, 1 Apr 2026 02:42:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.201.69 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011358; cv=fail; b=pHqkv41jIbKsUurWZ/ZtbYmwztMI4UNrRXSFwMBNfoeNYxVInBiIf6n1dopPcJ0x7t9v420VptxwAWSFQbuV4E5tPD3oKvjLHSZEdNKPjWyzNzBz9rAsKuJutp74GIHLbrnkGjadLKovHkGxak4wH1d9WCLPLheYgRh4j/eiAZ4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011358; c=relaxed/simple; bh=JuHd2GgdK2HSkTZZfPjM1XvwWEWf8MsDnvE2quVKkmQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JO+5cAOEU6zxiTVnK5r9TMv/ApC//Vgp660haQCsz1gPbTsUo+FKEZyhGH0gi4lhRTDg7//4Uf8lLwYnC7hzqNQL6m43dxA8SLUC9I0n7Seyowjo3129BGhSONpX/MBSz39MvGQMo9xvrSvpv5Nb7OZMMCL3IeTuJhIaBZ8H/XQ= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=uVmx898C; arc=fail smtp.client-ip=40.93.201.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="uVmx898C" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=adu5uowAXdAqfCXDduHx2GrHuNgQkpc5/5EwJEz0NyNVLf2b/YcrGMPPrwTQ6hbjtcox6PqC9VJS77CmHCQbl+XmhbwoF9ZJk2ms99LMtx82rxOAtYseqwHeZG2y/lNJn5C9Bc7W+wHg9oB7JPPk0b/IglcOEGzRCEvGpChFcLyBtcCYMvQeaLgGJ7n43TLM9eKzEclJjssNYHdUb2eZlOspKOmTAnN0YiKKBrU+/LGOBUo9B4cWaUFCvzhgK3wH7exgHhuqIKvF5rcKdVWW7jkFBGHkJiyQ5xUYyZXtEsskIxqSE4qy150JHIbCGwWJj3OauW+nJnzI2mT/2RVJNA== 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=mmwZuTujvRx4D7SsKvAskxGnQj4kuZ9nF03UvVixOxk=; b=uMVqWl2jlCuskZEclA5EAq3NWj8pvEpwhmzAyxAN3pg5RlkaW5UdeeDAWdqsCHkcpcoSxTfs7OBcpNNrnXP8M8ZbQCk/bRpoWxbRTvVnZ9Pux0+KjfGnQTsygEKOq/jPYexWLw6t+rc2RsC2X6+kaXzHKSbfxMFrl6ujCqJK1fM+ki4NeBRmn6KsYW74Rzw6+siOgjcePGxReLB9JQBfn6Hkpac2ek3hNlGw/XUfA7FxgQArFTBYA/r/z9vdD1edjiFZJdkEyQu/UnIMgTRmN/up02hf9VhEYbyb4eB4d30VIYaMgbgZ/rZ3Ql9ZDg5AtjUeYJcVqwW2TAYl6/F8EA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.23.194) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=ti.com; dmarc=pass (p=quarantine sp=none pct=100) action=none header.from=ti.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=mmwZuTujvRx4D7SsKvAskxGnQj4kuZ9nF03UvVixOxk=; b=uVmx898Cd1efs1IajRgPJ3tK4VYSmVGFI6iIs8IExIpYreBYMrm6NyYjS2sAecrHzyokSsx8kJnahIM+On5GZc+ce+TLf9q/yyAJT5yblidueW68vvS/2iEGrSqIZBK+pUi/1kM/UcX0lpzDe7+oLQO7NZ91sckUgzDaMAIa6J4= Received: from SJ0PR13CA0030.namprd13.prod.outlook.com (2603:10b6:a03:2c0::35) by IA3PR10MB8563.namprd10.prod.outlook.com (2603:10b6:208:571::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.17; Wed, 1 Apr 2026 02:42:19 +0000 Received: from SJ1PEPF00002320.namprd03.prod.outlook.com (2603:10b6:a03:2c0:cafe::ed) by SJ0PR13CA0030.outlook.office365.com (2603:10b6:a03:2c0::35) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.15 via Frontend Transport; Wed, 1 Apr 2026 02:42:18 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.23.194) smtp.mailfrom=ti.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=ti.com; Received-SPF: Pass (protection.outlook.com: domain of ti.com designates 198.47.23.194 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.23.194; helo=lewvzet200.ext.ti.com; pr=C Received: from lewvzet200.ext.ti.com (198.47.23.194) by SJ1PEPF00002320.mail.protection.outlook.com (10.167.242.86) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.21 via Frontend Transport; Wed, 1 Apr 2026 02:42:18 +0000 Received: from DLEE200.ent.ti.com (157.170.170.75) by lewvzet200.ext.ti.com (10.4.14.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:15 -0500 Received: from DLEE208.ent.ti.com (157.170.170.97) by DLEE200.ent.ti.com (157.170.170.75) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:15 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) by DLEE208.ent.ti.com (157.170.170.97) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Tue, 31 Mar 2026 21:42:15 -0500 Received: from localhost (mz02jj9v.dhcp.ti.com [128.247.81.246]) by lelvem-mr05.itg.ti.com (8.18.1/8.18.1) with ESMTP id 6312gFK43899100; Tue, 31 Mar 2026 21:42:15 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH 1/4] dt-bindings: sound: Add ti,tas675x Date: Tue, 31 Mar 2026 21:42:06 -0500 Message-ID: <20260401024210.28542-2-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401024210.28542-1-sen@ti.com> References: <20260401024210.28542-1-sen@ti.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-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ1PEPF00002320:EE_|IA3PR10MB8563:EE_ X-MS-Office365-Filtering-Correlation-Id: b8ec070f-4215-4b69-cde8-08de8f984ac9 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|1800799024|376014|7416014|36860700016|22082099003|56012099003|18002099003; X-Microsoft-Antispam-Message-Info: XGpPgRP2zR+Gkigd7wwzn14zDzvQ7uN3CSGMLzQCdjyKvAupyEXk2inIvGZS/s6lqzVb3tS6NK+DqtpaRzybA8DNMy5xxtusjh78P8rtz2TcXGMLfTpsu7Tu6GfxWbsZiqYPxzck9L/rcaJ20P4+5McJ49ZhCLe7bmiSPvAj8exlZcjBpB8c6WankfJVldU5Hcc7rqvDm1nE8F881dVxDtuQVb7hAHBWgNKVqoA3SN0rqgdoPkL4BBQWx4e0KAR/rj2Ik1M6o5S1d4IXwqXonJJXAsdt7IixbwlBMEfqdSPRk3vOKnRQFNQlyDkdp+AtIN3NW/kXb6An6W5JSuqOQu3OM5nI61iRtvMb4Kt1vztmG59tm5ZPEsSIh2HiFFH+NA1BzL1wTo2PizN8UgQzULkwwR9gidzdzWjDIxc4CunY0z6ld8mSvblbo2RUtrturTbulnf90j2n6yRALhdTCN1IrzFBUg+GgkHdtuuBEVjDJrVQZwqYlFHgCB/1T+6JR0LClliRvvMF/kenkNOHo+HA6zjSlQyn/QN6PwCazYgW1PuLGCzI8hhbNXSj69KqPMvZ6hoe+yiRy19o52Ay3wn1ILPW+uhWVQwPWGoP5UrEnxiaZ9q2NC7Ccta98+CgjP1EjiwN5rPr00Tq0QEkV5Q+OhoBqJvPivgMTMxinQ7mPc+1u/T+3m+GYTBVhpzwWfp1HN0HXTvwgO3P04RAU3RDZQ1J5cLFXmtnL8o/KLM= X-Forefront-Antispam-Report: CIP:198.47.23.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:lewvzet200.ext.ti.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(1800799024)(376014)(7416014)(36860700016)(22082099003)(56012099003)(18002099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: gcC283PITdOMxw6f4NEHU5wy9XYsYRX8udKuZuyk1JlvCOiewJbPbX/ir4GXoFsOr98UXsiov2pR30G+tnZrSTLyyLmX7DhvKQpSWmolVYT7Sho/Bet1Go5FociatjbPY/P1sB5oq5/iv1+l+Czmglmg19tyO0dumw66kulemPeqFYc77ImxxKJ8T4jY0Cr5Ejf64J2nyVw8jqjMfYid6qL5dIs1k9MoeDeGSYEvUSYtjp03biu57pqYxQ8G37hQ/iJdBnYHzZJDFHSWn2AtrrGlmgjwI3IU9dXPXj80ruNl9hfv0mgHmatcKek8jn7z7DSM6EJHp2UA4EsHSj1D47AQn3W19WZRIM+d3CDopmB1tMOKE7kuuhXzdWo0Vo1tx+tFjQ6yRawpYhcvwaTzccwysFNc2eu2hSUoAupN+HDDmcoGW+L//BAN+Aee1YvV X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 02:42:18.4409 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: b8ec070f-4215-4b69-cde8-08de8f984ac9 X-MS-Exchange-CrossTenant-Id: e5b49634-450b-4709-8abb-1e2b19b982b7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=e5b49634-450b-4709-8abb-1e2b19b982b7;Ip=[198.47.23.194];Helo=[lewvzet200.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: SJ1PEPF00002320.namprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: IA3PR10MB8563 Content-Type: text/plain; charset="utf-8" Add device tree binding for the Texas Instruments TAS675x family of four-channel Class-D audio amplifiers with integrated DSP. Signed-off-by: Sen Wang --- .../devicetree/bindings/sound/ti,tas675x.yaml | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ti,tas675x.yaml diff --git a/Documentation/devicetree/bindings/sound/ti,tas675x.yaml b/Docu= mentation/devicetree/bindings/sound/ti,tas675x.yaml new file mode 100644 index 000000000000..23e4cc77b4ae --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tas675x.yaml @@ -0,0 +1,278 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,tas675x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TAS675x Audio Amplifier + +maintainers: + - Sen Wang + +description: | + The TAS675x family (TAS6754, TAS67524) are four-channel, digital-input, + automotive Class-D audio amplifiers with load diagnostics and an integra= ted + DSP for audio processing. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + enum: + - ti,tas6754 + - ti,tas67524 + + reg: + maxItems: 1 + + '#sound-dai-cells': + const: 1 + description: | + The device exposes three DAIs, selected by index. + 0 - Standard Audio Path (Playback) + 1 - Low-Latency Playback Path (Playback) + 2 - Sensory Feedback (Capture - Vpredict and Isense) + By default, all four channels of each DAI are active. Runtime + reconfiguration is available through DAPM widgets. + + interrupts: + maxItems: 1 + description: + Active-low falling-edge interrupt from the FAULT pin. When provided, + the driver uses IRQ-driven fault reporting instead of polling. + + pd-gpios: + maxItems: 1 + description: + GPIO connected to the power-down (PD#) pin, active low. Controls the + internal digital circuitry power state. When asserted the device ent= ers + full power-down mode and all register state is lost. Can be omitted = if + PD pin is hardwired or externally controlled. + + stby-gpios: + maxItems: 1 + description: + GPIO connected to the standby (STBY#) pin, active low. Controls the + analog power stage. When asserted the device enters Deep Sleep mode + but remains I2C-accessible with registers retained. Can be omitted if + STBY pin is tied to PD or hardwired. + + dvdd-supply: + description: + Digital logic supply (1.62 V to 3.6 V). All three supply rails must + be within their recommended operating ranges before the PD pin is + released. + + pvdd-supply: + description: + Output FET power supply (4.5 V to 19 V). All three supply rails must + be within their recommended operating ranges before the PD pin is + released. + + vbat-supply: + description: + Battery supply for the Class-D output stage (4.5 V to 19 V). Optional + when PVDD and VBAT are connected to the same supply rail. When absen= t, + VBAT is assumed hardwired to PVDD. + + ti,fast-boot: + type: boolean + description: + Skip DC load diagnostic sweep at power-on to reduce boot latency. + Automatic diagnostics after fault conditions remain enabled. Hardware + overcurrent protection is always active. + + ti,audio-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + TDM slot offset for the standard audio playback path via SDIN1. A va= lue + of 4 maps to slot 4. If omitted, slot assignment is derived from the + tx_mask provided via set_tdm_slot(). Without either property, no slot + mapping is configured. + + ti,llp-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + TDM slot offset for the low-latency playback path via SDIN1. If omit= ted, + slot assignment is derived from the tx_mask provided via set_tdm_slo= t(). + Without either property, no slot mapping is configured. Disabled out= side + of LLP mode, and only relevant for TDM formats. + + ti,vpredict-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + In TDM mode, enables Vpredict output and assigns its starting slot; + four consecutive slots carry Vpredict Ch1-4 on SDOUT1. May coexist + with ti,isense-slot-no using separate non-overlapping slots. + + In I2S mode, enables Vpredict output on SDOUT1 (Ch1/Ch2) and SDOUT2 + (Ch3/Ch4). The slot value is unused. Requires a GPIO configured as + sdout2 for Ch3/Ch4; without it only Ch1/Ch2 are output. Mutually + exclusive with ti,isense-slot-no; if both are set, Vpredict takes + priority. + + Irrelevant in Left-J and Right-J modes. + + ti,isense-slot-no: + $ref: /schemas/types.yaml#/definitions/uint32 + description: | + In TDM mode, enables Isense output and assigns its starting slot; + four consecutive slots carry Isense Ch1-4 on SDOUT1. May coexist + with ti,vpredict-slot-no using separate non-overlapping slots. + + In I2S mode, enables Isense output on SDOUT1 (Ch1/Ch2) and SDOUT2 + (Ch3/Ch4). The slot value is unused. Requires a GPIO configured as + sdout2 for Ch3/Ch4; without it only Ch1/Ch2 are output. Mutually + exclusive with ti,vpredict-slot-no; Vpredict takes priority if both + are set. + + Irrelevant in Left-J and Right-J modes. + + ti,gpio1-function: + $ref: /schemas/types.yaml#/definitions/string + description: | + Function for the GPIO_1 pin. When omitted, GPIO_1 remains in its + power-on default state. + enum: + - low # Output: driven low + - auto-mute # Output: high when all channels are auto-muted + - auto-mute-ch4 # Output: high when channel 4 is auto-muted + - auto-mute-ch3 # Output: high when channel 3 is auto-muted + - auto-mute-ch2 # Output: high when channel 2 is auto-muted + - auto-mute-ch1 # Output: high when channel 1 is auto-muted + - sdout2 # Output: Routes secondary serial data output 2 + - sdout1 # Output: Re-routes secondary serial data output 1 + - warn # Output: warning signal (OTW, CBC) + - fault # Output: fault signal (OTSD, OC, DC) + - clock-sync # Output: clock synchronisation + - invalid-clock # Output: high when clock is invalid + - high # Output: driven high + - mute # Input: external mute control + - phase-sync # Input: phase synchronisation + - sdin2 # Input: secondary SDIN2 for I2S/LJ/RJ ch3/ch4 + - deep-sleep # Input: asserted transitions device to Deep Sleep + - hiz # Input: asserted transitions device to Hi-Z + - play # Input: asserted transitions device to Play + - sleep # Input: asserted transitions device to Sleep + + ti,gpio2-function: + $ref: /schemas/types.yaml#/definitions/string + description: | + Function for the GPIO_2 pin. When omitted, GPIO_2 remains in its + power-on default state. + enum: + - low # Output: driven low + - auto-mute # Output: high when all channels are auto-muted + - auto-mute-ch4 # Output: high when channel 4 is auto-muted + - auto-mute-ch3 # Output: high when channel 3 is auto-muted + - auto-mute-ch2 # Output: high when channel 2 is auto-muted + - auto-mute-ch1 # Output: high when channel 1 is auto-muted + - sdout2 # Output: Routes secondary serial data output 2 + - sdout1 # Output: Re-routes secondary serial data output 1 + - warn # Output: warning signal (OTW, CBC) + - fault # Output: fault signal (OTSD, OC, DC) + - clock-sync # Output: clock synchronisation + - invalid-clock # Output: high when clock is invalid + - high # Output: driven high + - mute # Input: external mute control + - phase-sync # Input: phase synchronisation + - sdin2 # Input: secondary SDIN2 for I2S/LJ/RJ ch3/ch4 + - deep-sleep # Input: asserted transitions device to Deep Sleep + - hiz # Input: asserted transitions device to Hi-Z + - play # Input: asserted transitions device to Play + - sleep # Input: asserted transitions device to Sleep + + ports: + $ref: /schemas/graph.yaml#/properties/ports + properties: + port@0: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: Standard audio playback port (DAI 0). + + port@1: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: Low-latency playback port (LLP) (DAI 1). + + port@2: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + description: Sensory feedback capture port (DAI 2). + + port: + $ref: audio-graph-port.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - '#sound-dai-cells' + - dvdd-supply + - pvdd-supply + +anyOf: + - required: [pd-gpios] + - required: [stby-gpios] + +unevaluatedProperties: false + +examples: + - | + #include + + i2c { + #address-cells =3D <1>; + #size-cells =3D <0>; + + amplifier@70 { + compatible =3D "ti,tas67524"; + reg =3D <0x70>; + #sound-dai-cells =3D <1>; + sound-name-prefix =3D "TAS0"; + + stby-gpios =3D <&main_gpio0 33 GPIO_ACTIVE_LOW>; + + dvdd-supply =3D <&dvdd_1v8>; + pvdd-supply =3D <&pvdd_12v>; + vbat-supply =3D <&vbat_12v>; + + ti,audio-slot-no =3D <0>; + ti,llp-slot-no =3D <4>; + ti,vpredict-slot-no =3D <0>; + ti,isense-slot-no =3D <4>; + + ti,gpio2-function =3D "warn"; + + ports { + #address-cells =3D <1>; + #size-cells =3D <0>; + + port@0 { + reg =3D <0>; + + tas0_audio_ep: endpoint { + dai-format =3D "dsp_b"; + remote-endpoint =3D <&be_tas0_audio_ep>; + }; + }; + + port@1 { + reg =3D <1>; + + tas0_anc_ep: endpoint { + remote-endpoint =3D <&be_tas0_anc_ep>; + }; + }; + + port@2 { + reg =3D <2>; + + tas0_fb_ep: endpoint { + remote-endpoint =3D <&be_tas0_fb_ep>; + }; + }; + }; + }; + }; --=20 2.43.0 From nobody Wed Apr 1 08:37:52 2026 Received: from BN8PR05CU002.outbound.protection.outlook.com (mail-eastus2azon11011070.outbound.protection.outlook.com [52.101.57.70]) (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 671EF201278; Wed, 1 Apr 2026 02:42:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.57.70 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011370; cv=fail; b=UEF/WOloUeYrV2w8tr2JjfP3BV8ub91u7ugKsRj+08DozRF7a07P1+Q5aig7ryJ+0VMeeFDB0rhB8B7HlOBDFUsUW0dw3UsDacYE0FEOvsCix+Q0BLPHhk7BcdiM9AYs7a1HvrF21eeA0tX3W/n+JD2P0BWnNPWUa0+Su1ElVng= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011370; c=relaxed/simple; bh=KyxpzFhzyHhIzTP4oV0jXu0Ym3lVOr7heNuQBMoFjS4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cu8QVgpQCMLHg022MbZDEOoDebavbPn7H/PK5yj1og08+S7LenzrcOBSimA5qs2qWVoAgNHQSg1cLzxibKk5sAk8s2LP4aF5FFepRi4UP0ch/2tv/SnRl7hxm//CKMvPPRMvMJEUD01unN4ZVDMg1B3K+eG1UXLN08mkgvwXlZ8= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=r8ZUXuJp; arc=fail smtp.client-ip=52.101.57.70 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="r8ZUXuJp" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=moQSeW8GVbDLBbmyeTtL4N+xbVq2NuUFuEwRwc3SB7/7yHGYw2LHS5jJ/PkTJzoR/bmyHzdeTdDrm7L+9SSZ5KgUBMZJFk+HjdBKCx0Ix3FpBjC/uX7C4amkXYYkE5tPGBPfwlvTp4KVvC+N6le2NcNOwWeyvpSxjSpRSrgJQnI8xKOyeVxlgG9M0TI5+z/h01mO5IgOld5S15BwOnR+qYm8RNrcFVBPoq6arynk+81domDEKP7SihPidko3L6CUkyTUbPWyZ0z1GH/KqFgOGxWsiVzpj/fsRaGBjSHy58bNJl0roO9jUeJYtyWldvkwu4j76qg1WyM0+Ubm7Q/8/w== 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=E6Np+6vv2WLBrdlljKPee+GWhmPVBXYgTzLZo5qSEuE=; b=FR/SMnkZJojNQO66b8GcTaF20Qhj+Bmqo0MbIac1ghxPUMr57fQtRVfV189khBCLFg993GdYELt+qssS4k96HvlCgV33WuHgir1lSilQph6oVUBVLSNCndEhKMeBKXW9UBGuGhJVjoa+0gu3s33pd8j0amQMHJxRAAu7d8uuydlemXYeqnDgw31zuknCqOmcaYFtZHY7EdQ8/xCfhz84a+2pIULEoSpiuTpAJwfWVCF2Fo6WFBZUYDJxQHZPxcapg31TeLt/qDwt2/oh4aJtJ/m60A5uFlug9ZuySBbcsWmTxGIjxSuO9qLlPshwmRRuwl0oOHEwwQAe+xPPYWrHUg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.21.194) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=ti.com; dmarc=pass (p=quarantine sp=none pct=100) action=none header.from=ti.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=E6Np+6vv2WLBrdlljKPee+GWhmPVBXYgTzLZo5qSEuE=; b=r8ZUXuJpRCPhQ2hbDmdMpxy/piUkNl4w78K6oQZzYL10cs0f5tknOvAXi2PbVPie7h4Csp9RIxvk676zuafhFSnhUEQ5HVbUbQ8WwWtg2XcYuX1cPi0nmi/K0Dt2SXq1w2aItdcBAaG5kWr+s3k4zEU7IWrrGwtLZvx5XIeiPrg= Received: from BN9PR03CA0268.namprd03.prod.outlook.com (2603:10b6:408:ff::33) by LV8PR10MB7798.namprd10.prod.outlook.com (2603:10b6:408:1f7::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.17; Wed, 1 Apr 2026 02:42:21 +0000 Received: from BN2PEPF000044A1.namprd02.prod.outlook.com (2603:10b6:408:ff:cafe::1) by BN9PR03CA0268.outlook.office365.com (2603:10b6:408:ff::33) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9745.29 via Frontend Transport; Wed, 1 Apr 2026 02:42:21 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.21.194) smtp.mailfrom=ti.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=ti.com; Received-SPF: Pass (protection.outlook.com: domain of ti.com designates 198.47.21.194 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.21.194; helo=flwvzet200.ext.ti.com; pr=C Received: from flwvzet200.ext.ti.com (198.47.21.194) by BN2PEPF000044A1.mail.protection.outlook.com (10.167.243.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.17 via Frontend Transport; Wed, 1 Apr 2026 02:42:19 +0000 Received: from DFLE210.ent.ti.com (10.64.6.68) by flwvzet200.ext.ti.com (10.248.192.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:16 -0500 Received: from DFLE208.ent.ti.com (10.64.6.66) by DFLE210.ent.ti.com (10.64.6.68) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:15 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) by DFLE208.ent.ti.com (10.64.6.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Tue, 31 Mar 2026 21:42:15 -0500 Received: from localhost (mz02jj9v.dhcp.ti.com [128.247.81.246]) by lelvem-mr05.itg.ti.com (8.18.1/8.18.1) with ESMTP id 6312gFMQ3899115; Tue, 31 Mar 2026 21:42:15 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH 2/4] ASoC: codecs: Add TAS675x quad-channel audio amplifier driver Date: Tue, 31 Mar 2026 21:42:07 -0500 Message-ID: <20260401024210.28542-3-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401024210.28542-1-sen@ti.com> References: <20260401024210.28542-1-sen@ti.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN2PEPF000044A1:EE_|LV8PR10MB7798:EE_ X-MS-Office365-Filtering-Correlation-Id: deec8057-9891-4e4b-2c41-08de8f984b99 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700016|7416014|376014|1800799024|82310400026|13003099007|18002099003|22082099003|56012099003; X-Microsoft-Antispam-Message-Info: LPvC7Zpl/9KYJp2mNuzbJ1T1NWODkCHCUrZGosnf0ORZYWFdDJker5HHT7mSmViVpG8sCYrG3QpsGjNOFsxwS+aLaUq522si3TgVc2X1IO5Z6A6Oq2bL2FL9zIKjuf7OXAfCvOyTwgbPY5scE0jdh05xzIEABYeoEUrcw8KDtoD5QVjC/rJzurUKmmMJlH8e+yIMzxrz4b8ilKOGPl9CcQeiy10uL+vewX6ExdJtUAtVwelp1NroPWYqiePW7v0ayIsHNoEUi55j5vkzLsAzDfCsRwsE1R/TT0jZublfqtYPmylI7dqUU3TbAl4yO8jW70XH1JdbJ2d9QhRsdizv4b4/geCdSVV1EtUAQQ6B44/TJV0NpxkFrWQenBPl6i1CFoerXVn8WAEY2cSJqn8kwezsq9Ssp3agt5inQEwqRojhzwbiAsgQD0qRiaFvvwgQrUSZDXv9dMSgBz14ne1HHNWZUdg7Da83pCseMI43/AxDsDO2A/aE/r6HtDh/tsdPM/OnbIiKl3D01KFJF8OOc0Llhh7vI+t7bN+U7uJMYISi3X/aM4uyxMCGST9TKlFNWJqmJOuaSmL3VKUImafYmw7Irf/2MN/safsS4ZqqVXhx9QF+SS49b1xYGwYwRDSJkaNI+lLc7Mn8oAcJ8phbSAQBDjmnXGD3RDL5i9JfJQ3hpywNQo5dAaRCuif4ToTt0Kh7rDOCTDVn9+Y7kR3cAnhzrNLSuKIt2MLS8OQ+H8A= X-Forefront-Antispam-Report: CIP:198.47.21.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:flwvzet200.ext.ti.com;PTR:ErrorRetry;CAT:NONE;SFS:(13230040)(36860700016)(7416014)(376014)(1800799024)(82310400026)(13003099007)(18002099003)(22082099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: qkOqZqFlQekKRc9SMsIulh93xiBqqrUg5pDRVZ8sJsmnixDLaXfikkPKVm86B3i/XyzYbhXLmU6Wzwe221f0GGnL9TDVsI5W95+QzXFYFQ0ykw2KQVfWZR6m1+67DoQEeGQMxjheatK8EJ5SE8hMVTnYVnATfK5rOqoFccb5nirWm1Z1aDal09bWd1XObcykZ6+kSu6hpxCd5SiVe6g/rZV1li8lRnjJF8IPxwvD3bmWDri6lCZuiBk7DfL+8AVWv6oUG2DymRKqQnTUHNcv/Hwld9iguRY3eLwXMzilZR5iMtDPaaseQmUWjoC50mJci83sBS7ANeSO9ATymtFVWnbpi+G+xPSJn8pLZkn2c58rHOCk3wMTsvhwB0jX0lSTpE6O7RgCR/2xnRTwOcAB92r6pS1Y4pdLtrqUP8zHk9EiY12wncEcRW9NovOFTEgJ X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 02:42:19.8101 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: deec8057-9891-4e4b-2c41-08de8f984b99 X-MS-Exchange-CrossTenant-Id: e5b49634-450b-4709-8abb-1e2b19b982b7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=e5b49634-450b-4709-8abb-1e2b19b982b7;Ip=[198.47.21.194];Helo=[flwvzet200.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: BN2PEPF000044A1.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV8PR10MB7798 The TAS675x (TAS6754, TAS67524) are quad-channel, digital-input Class-D amplifiers with an integrated DSP, controlled over I2C. They support I2S and TDM serial audio interfaces. The driver exposes three DAI endpoints: standard playback, a low-latency DSP bypass path, and a sense capture DAI for real-time voltage and current feedback. DC, AC and real-time load diagnostics and hardware fault monitoring are supported. Link: https://www.ti.com/product/TAS6754-Q1 Signed-off-by: Sen Wang --- sound/soc/codecs/Kconfig | 12 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas675x.c | 2172 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas675x.h | 367 ++++++ 4 files changed, 2553 insertions(+) create mode 100644 sound/soc/codecs/tas675x.c create mode 100644 sound/soc/codecs/tas675x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f9e6a83e55c6..0ca7c7e2283b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -275,6 +275,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_TAS571X imply SND_SOC_TAS5720 imply SND_SOC_TAS6424 + imply SND_SOC_TAS675X imply SND_SOC_TDA7419 imply SND_SOC_TFA9879 imply SND_SOC_TFA989X @@ -2240,6 +2241,17 @@ config SND_SOC_TAS6424 Enable support for Texas Instruments TAS6424 high-efficiency digital input quad-channel Class-D audio power amplifiers. =20 +config SND_SOC_TAS675X + tristate "Texas Instruments TAS675x Quad-Channel Audio Amplifier" + depends on I2C + select REGMAP_I2C + help + Enable support for Texas Instruments TAS675x quad-channel Class-D + audio power amplifiers (TAS6754, TAS67524). The devices support I2S + and TDM interfaces with real-time voltage and current sense feedback + via SDOUT, and provide DC/AC/real-time load diagnostics for speaker + monitoring. + config SND_SOC_TDA7419 tristate "ST TDA7419 audio processor" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 172861d17cfd..106fdc140d42 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -318,6 +318,7 @@ snd-soc-tas571x-y :=3D tas571x.o snd-soc-tas5720-y :=3D tas5720.o snd-soc-tas5805m-y :=3D tas5805m.o snd-soc-tas6424-y :=3D tas6424.o +snd-soc-tas675x-y :=3D tas675x.o snd-soc-tda7419-y :=3D tda7419.o snd-soc-tas2770-y :=3D tas2770.o snd-soc-tas2781-comlib-y :=3D tas2781-comlib.o @@ -760,6 +761,7 @@ obj-$(CONFIG_SND_SOC_TAS571X) +=3D snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TAS5720) +=3D snd-soc-tas5720.o obj-$(CONFIG_SND_SOC_TAS5805M) +=3D snd-soc-tas5805m.o obj-$(CONFIG_SND_SOC_TAS6424) +=3D snd-soc-tas6424.o +obj-$(CONFIG_SND_SOC_TAS675X) +=3D snd-soc-tas675x.o obj-$(CONFIG_SND_SOC_TDA7419) +=3D snd-soc-tda7419.o obj-$(CONFIG_SND_SOC_TAS2770) +=3D snd-soc-tas2770.o obj-$(CONFIG_SND_SOC_TFA9879) +=3D snd-soc-tfa9879.o diff --git a/sound/soc/codecs/tas675x.c b/sound/soc/codecs/tas675x.c new file mode 100644 index 000000000000..cf150a115bb3 --- /dev/null +++ b/sound/soc/codecs/tas675x.c @@ -0,0 +1,2172 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALSA SoC Texas Instruments TAS675x Quad-Channel Audio Amplifier + * + * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/ + * Author: Sen Wang + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas675x.h" + +#define TAS675X_FAULT_CHECK_INTERVAL_MS 200 + +enum tas675x_type { + TAS6754, +}; + +struct tas675x_reg_param { + u8 page; + u8 reg; + u32 val; +}; + +struct tas675x_priv { + struct device *dev; + struct regmap *regmap; + enum tas675x_type dev_type; + struct mutex io_lock; + + struct gpio_desc *pd_gpio; + struct gpio_desc *stby_gpio; + struct regulator_bulk_data supplies[2]; + struct regulator *vbat; + bool fast_boot; + + int audio_slot; + int llp_slot; + int vpredict_slot; + int isense_slot; + int bclk_offset; + int slot_width; + unsigned int tx_mask; + + int gpio1_func; + int gpio2_func; + + unsigned long active_playback_dais; + unsigned long active_capture_dais; + unsigned int rate; + unsigned int saved_rtldg_en; +#define TAS675X_DSP_PARAM_NUM 2 + struct tas675x_reg_param dsp_params[TAS675X_DSP_PARAM_NUM]; + + /* Fault monitor, disabled when Fault IRQ is used */ + struct delayed_work fault_check_work; +#define TAS675X_FAULT_REGS_NUM 8 + unsigned int last_status[TAS675X_FAULT_REGS_NUM]; +}; + +static const char * const tas675x_supply_names[] =3D { + "dvdd", /* Digital power supply */ + "pvdd", /* Output powerstage supply */ +}; + +/* Page 1 setup initialization defaults */ +static const struct reg_sequence tas675x_page1_init[] =3D { + REG_SEQ0(TAS675X_PAGE_REG(1, 0xC8), 0x20), /* Charge pump clock */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0x2F), 0x90), /* VBAT idle */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0x29), 0x40), /* OC/CBC threshold */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0x2E), 0x0C), /* OC/CBC config */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0xC5), 0x02), /* OC/CBC config */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0xC6), 0x10), /* OC/CBC config */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0x1F), 0x20), /* OC/CBC config */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0x16), 0x01), /* OC/CBC config */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0x1E), 0x04), /* OC/CBC config */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0xC1), 0x00), /* CH1 DC fault */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0xC2), 0x04), /* CH2 DC fault */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0xC3), 0x00), /* CH3 DC fault */ + REG_SEQ0(TAS675X_PAGE_REG(1, 0xC4), 0x00), /* CH4 DC fault */ +}; + +static inline const char *tas675x_state_name(unsigned int state) +{ + switch (state & 0x0F) { + case TAS675X_STATE_DEEPSLEEP: return "DEEPSLEEP"; + case TAS675X_STATE_LOAD_DIAG: return "LOAD_DIAG"; + case TAS675X_STATE_SLEEP: return "SLEEP"; + case TAS675X_STATE_HIZ: return "HIZ"; + case TAS675X_STATE_PLAY: return "PLAY"; + case TAS675X_STATE_FAULT: return "FAULT"; + case TAS675X_STATE_AUTOREC: return "AUTOREC"; + default: return "UNKNOWN"; + } +} + +static inline int tas675x_set_state_all(struct tas675x_priv *tas, u8 state) +{ + const struct reg_sequence seq[] =3D { + REG_SEQ0(TAS675X_STATE_CTRL_CH1_CH2_REG, state), + REG_SEQ0(TAS675X_STATE_CTRL_CH3_CH4_REG, state), + }; + + return regmap_multi_reg_write(tas->regmap, seq, ARRAY_SIZE(seq)); +} + +static inline int tas675x_select_book(struct regmap *regmap, u8 book) +{ + int ret; + + /* Reset page to 0 before switching books */ + ret =3D regmap_write(regmap, TAS675X_PAGE_CTRL_REG, 0x00); + if (!ret) + ret =3D regmap_write(regmap, TAS675X_BOOK_CTRL_REG, book); + + return ret; +} + +/* Raw I2C version of tas675x_select_book, must be called with io_lock hel= d */ +static inline int __tas675x_select_book(struct tas675x_priv *tas, u8 book) +{ + struct i2c_client *client =3D to_i2c_client(tas->dev); + int ret; + + /* Reset page to 0 before switching books */ + ret =3D i2c_smbus_write_byte_data(client, TAS675X_PAGE_CTRL_REG, 0x00); + if (ret) + return ret; + + return i2c_smbus_write_byte_data(client, TAS675X_BOOK_CTRL_REG, book); +} + +static int tas675x_dsp_mem_write(struct tas675x_priv *tas, u8 page, u8 reg= , u32 val) +{ + struct i2c_client *client =3D to_i2c_client(tas->dev); + u8 buf[4]; + int ret; + + /* DSP registers are 24-bit values, zero-padded MSB to 32-bit */ + buf[0] =3D 0x00; + buf[1] =3D (val >> 16) & 0xFF; + buf[2] =3D (val >> 8) & 0xFF; + buf[3] =3D val & 0xFF; + + /* + * DSP regs in a different book, therefore block + * regmap access before completion. + */ + mutex_lock(&tas->io_lock); + + ret =3D __tas675x_select_book(tas, TAS675X_BOOK_DSP); + if (ret) + goto out; + + ret =3D i2c_smbus_write_byte_data(client, TAS675X_PAGE_CTRL_REG, page); + if (ret) + goto out; + + ret =3D i2c_smbus_write_i2c_block_data(client, reg, sizeof(buf), buf); + +out: + __tas675x_select_book(tas, TAS675X_BOOK_DEFAULT); + mutex_unlock(&tas->io_lock); + + return ret; +} + +static int tas675x_dsp_mem_read(struct tas675x_priv *tas, u8 page, u8 reg,= u32 *val) +{ + struct i2c_client *client =3D to_i2c_client(tas->dev); + u8 buf[4]; + int ret; + + /* + * DSP regs in a different book, therefore block + * regmap access before completion. + */ + mutex_lock(&tas->io_lock); + + ret =3D __tas675x_select_book(tas, TAS675X_BOOK_DSP); + if (ret) + goto out; + + ret =3D i2c_smbus_write_byte_data(client, TAS675X_PAGE_CTRL_REG, page); + if (ret) + goto out; + + ret =3D i2c_smbus_read_i2c_block_data(client, reg, sizeof(buf), buf); + if (ret =3D=3D sizeof(buf)) { + *val =3D (buf[1] << 16) | (buf[2] << 8) | buf[3]; + ret =3D 0; + } else if (ret >=3D 0) { + ret =3D -EIO; + } + +out: + __tas675x_select_book(tas, TAS675X_BOOK_DEFAULT); + mutex_unlock(&tas->io_lock); + + return ret; +} + +static const struct { + const char *name; + int val; +} tas675x_gpio_func_map[] =3D { + /* Output functions */ + { "low", TAS675X_GPIO_SEL_LOW }, + { "auto-mute", TAS675X_GPIO_SEL_AUTO_MUTE_ALL }, + { "auto-mute-ch4", TAS675X_GPIO_SEL_AUTO_MUTE_CH4 }, + { "auto-mute-ch3", TAS675X_GPIO_SEL_AUTO_MUTE_CH3 }, + { "auto-mute-ch2", TAS675X_GPIO_SEL_AUTO_MUTE_CH2 }, + { "auto-mute-ch1", TAS675X_GPIO_SEL_AUTO_MUTE_CH1 }, + { "sdout2", TAS675X_GPIO_SEL_SDOUT2 }, + { "sdout1", TAS675X_GPIO_SEL_SDOUT1 }, + { "warn", TAS675X_GPIO_SEL_WARN }, + { "fault", TAS675X_GPIO_SEL_FAULT }, + { "clock-sync", TAS675X_GPIO_SEL_CLOCK_SYNC }, + { "invalid-clock", TAS675X_GPIO_SEL_INVALID_CLK }, + { "high", TAS675X_GPIO_SEL_HIGH }, + /* Input functions */ + { "mute", TAS675X_GPIO_IN_MUTE }, + { "phase-sync", TAS675X_GPIO_IN_PHASE_SYNC }, + { "sdin2", TAS675X_GPIO_IN_SDIN2 }, + { "deep-sleep", TAS675X_GPIO_IN_DEEP_SLEEP }, + { "hiz", TAS675X_GPIO_IN_HIZ }, + { "play", TAS675X_GPIO_IN_PLAY }, + { "sleep", TAS675X_GPIO_IN_SLEEP }, +}; + +static int tas675x_gpio_func_parse(struct device *dev, const char *propnam= e) +{ + const char *str; + int i, ret; + + ret =3D device_property_read_string(dev, propname, &str); + if (ret) + return -1; + + for (i =3D 0; i < ARRAY_SIZE(tas675x_gpio_func_map); i++) { + if (!strcmp(str, tas675x_gpio_func_map[i].name)) + return tas675x_gpio_func_map[i].val; + } + + dev_warn(dev, "Invalid %s value '%s'\n", propname, str); + return -1; +} + +static const struct { + unsigned int reg; + unsigned int mask; +} tas675x_gpio_input_table[TAS675X_GPIO_IN_NUM] =3D { + [TAS675X_GPIO_IN_ID_MUTE] =3D { + TAS675X_GPIO_INPUT_MUTE_REG, TAS675X_GPIO_IN_MUTE_MASK }, + [TAS675X_GPIO_IN_ID_PHASE_SYNC] =3D { + TAS675X_GPIO_INPUT_SYNC_REG, TAS675X_GPIO_IN_SYNC_MASK }, + [TAS675X_GPIO_IN_ID_SDIN2] =3D { + TAS675X_GPIO_INPUT_SDIN2_REG, TAS675X_GPIO_IN_SDIN2_MASK }, + [TAS675X_GPIO_IN_ID_DEEP_SLEEP] =3D { + TAS675X_GPIO_INPUT_SLEEP_HIZ_REG, TAS675X_GPIO_IN_DEEP_SLEEP_MASK }, + [TAS675X_GPIO_IN_ID_HIZ] =3D { + TAS675X_GPIO_INPUT_SLEEP_HIZ_REG, TAS675X_GPIO_IN_HIZ_MASK }, + [TAS675X_GPIO_IN_ID_PLAY] =3D { + TAS675X_GPIO_INPUT_PLAY_SLEEP_REG, TAS675X_GPIO_IN_PLAY_MASK }, + [TAS675X_GPIO_IN_ID_SLEEP] =3D { + TAS675X_GPIO_INPUT_PLAY_SLEEP_REG, TAS675X_GPIO_IN_SLEEP_MASK }, +}; + +static void tas675x_config_gpio_pin(struct regmap *regmap, int func_id, + unsigned int out_sel_reg, + unsigned int pin_idx, + unsigned int *gpio_ctrl) +{ + int id; + + if (func_id < 0) + return; + + if (func_id & TAS675X_GPIO_FUNC_INPUT) { + /* 3-bit mux: 0 =3D disabled, 0b1 =3D GPIO1, 0b10 =3D GPIO2 */ + id =3D func_id & ~TAS675X_GPIO_FUNC_INPUT; + regmap_update_bits(regmap, + tas675x_gpio_input_table[id].reg, + tas675x_gpio_input_table[id].mask, + (pin_idx + 1) << __ffs(tas675x_gpio_input_table[id].mask)); + } else { + /* Output GPIO, update selection register and enable bit */ + regmap_write(regmap, out_sel_reg, func_id); + *gpio_ctrl |=3D pin_idx ? TAS675X_GPIO2_OUTPUT_EN : TAS675X_GPIO1_OUTPUT= _EN; + } +} + +static int tas675x_rtldg_thresh_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count =3D 1; + uinfo->value.integer.min =3D 0; + /* Accepts 32-bit values, even though 8bit MSB is ignored */ + uinfo->value.integer.max =3D 0xFFFFFFFF; + return 0; +} + +static int tas675x_set_rtldg_thresh(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp =3D snd_kcontrol_chip(kcontrol); + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(comp); + const struct tas675x_reg_param *t =3D + (const struct tas675x_reg_param *)kcontrol->private_value; + u32 val =3D ucontrol->value.integer.value[0]; + int ret; + + ret =3D tas675x_dsp_mem_write(tas, t->page, t->reg, val); + + /* Cache the value */ + if (!ret) { + int i; + + for (i =3D 0; i < ARRAY_SIZE(tas->dsp_params); i++) { + if (tas->dsp_params[i].page =3D=3D t->page && + tas->dsp_params[i].reg =3D=3D t->reg) { + tas->dsp_params[i].val =3D val; + break; + } + } + } + + /* Return 1 to notify change, or propagate error */ + return ret ? ret : 1; +} + +static int tas675x_get_rtldg_thresh(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp =3D snd_kcontrol_chip(kcontrol); + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(comp); + const struct tas675x_reg_param *t =3D + (const struct tas675x_reg_param *)kcontrol->private_value; + u32 val =3D 0; + int ret; + + ret =3D tas675x_dsp_mem_read(tas, t->page, t->reg, &val); + if (!ret) + ucontrol->value.integer.value[0] =3D val; + + return ret; +} + +static const struct tas675x_reg_param tas675x_dsp_defaults[] =3D { + [TAS675X_DSP_PARAM_ID_OL_THRESH] =3D { + TAS675X_DSP_PAGE_RTLDG, TAS675X_DSP_RTLDG_OL_THRESH_REG }, + [TAS675X_DSP_PARAM_ID_SL_THRESH] =3D { + TAS675X_DSP_PAGE_RTLDG, TAS675X_DSP_RTLDG_SL_THRESH_REG }, +}; + +static int tas675x_set_dcldg_trigger(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp =3D snd_kcontrol_chip(kcontrol); + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(comp); + unsigned int state, state34; + int ret; + + if (!ucontrol->value.integer.value[0]) + return 0; + + if (snd_soc_component_active(comp)) + return -EBUSY; + + ret =3D pm_runtime_resume_and_get(tas->dev); + if (ret < 0) + return ret; + + /* + * Abort automatic DC LDG retry loops (startup or init-after-fault) + * and clear faults before manual diagnostics. + */ + regmap_update_bits(tas->regmap, TAS675X_DC_LDG_CTRL_REG, + TAS675X_LDG_ABORT_BIT | TAS675X_LDG_BYPASS_BIT, + TAS675X_LDG_ABORT_BIT | TAS675X_LDG_BYPASS_BIT); + regmap_write(tas->regmap, TAS675X_RESET_REG, TAS675X_FAULT_CLEAR); + + /* Wait for LOAD_DIAG to exit */ + regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH1_CH2_REG, + state, (state & 0x0F) !=3D TAS675X_STATE_LOAD_DIAG && + (state >> 4) !=3D TAS675X_STATE_LOAD_DIAG, + TAS675X_POLL_INTERVAL_US, + TAS675X_STATE_TRANSITION_TIMEOUT_US); + regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH3_CH4_REG, + state34, (state34 & 0x0F) !=3D TAS675X_STATE_LOAD_DIAG && + (state34 >> 4) !=3D TAS675X_STATE_LOAD_DIAG, + TAS675X_POLL_INTERVAL_US, + TAS675X_STATE_TRANSITION_TIMEOUT_US); + + /* Transition to HIZ state */ + ret =3D tas675x_set_state_all(tas, TAS675X_STATE_HIZ_BOTH); + if (ret) + goto out_restore_ldg_ctrl; + + /* Set LOAD_DIAG state for manual DC LDG */ + ret =3D tas675x_set_state_all(tas, TAS675X_STATE_LOAD_DIAG_BOTH); + if (ret) + goto out_restore_ldg_ctrl; + + /* Wait for device to transition to LOAD_DIAG state */ + regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH1_CH2_REG, + state, state =3D=3D TAS675X_STATE_LOAD_DIAG_BOTH, + TAS675X_POLL_INTERVAL_US, + TAS675X_STATE_TRANSITION_TIMEOUT_US); + regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH3_CH4_REG, + state34, state34 =3D=3D TAS675X_STATE_LOAD_DIAG_BOTH, + TAS675X_POLL_INTERVAL_US, + TAS675X_STATE_TRANSITION_TIMEOUT_US); + + /* Clear ABORT and BYPASS bits to enable manual DC LDG */ + ret =3D regmap_update_bits(tas->regmap, TAS675X_DC_LDG_CTRL_REG, + TAS675X_LDG_ABORT_BIT | TAS675X_LDG_BYPASS_BIT, + 0); + if (ret) + goto out_restore_hiz; + + dev_dbg(tas->dev, "DC LDG: Started\n"); + + /* Poll all channels for SLEEP state */ + ret =3D regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH1_CH= 2_REG, + state, state =3D=3D TAS675X_STATE_SLEEP_BOTH, + TAS675X_POLL_INTERVAL_US, + TAS675X_DC_LDG_TIMEOUT_US); + ret |=3D regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH3_C= H4_REG, + state34, state34 =3D=3D TAS675X_STATE_SLEEP_BOTH, + TAS675X_POLL_INTERVAL_US, + TAS675X_DC_LDG_TIMEOUT_US); + if (ret) { + dev_err(tas->dev, + "DC LDG: timeout (CH1/2=3D0x%02x [%s/%s], CH3/4=3D0x%02x [%s/%s])\n", + state, tas675x_state_name(state), tas675x_state_name(state >> 4), + state34, tas675x_state_name(state34), tas675x_state_name(state34 >> 4)); + goto out_restore_hiz; + } + + dev_dbg(tas->dev, "DC LDG: Completed successfully (CH1/2=3D0x%02x, CH3/4= =3D0x%02x)\n", + state, state34); + +out_restore_hiz: + tas675x_set_state_all(tas, TAS675X_STATE_HIZ_BOTH); + +out_restore_ldg_ctrl: + regmap_update_bits(tas->regmap, TAS675X_DC_LDG_CTRL_REG, + TAS675X_LDG_ABORT_BIT | TAS675X_LDG_BYPASS_BIT, + 0); + + pm_runtime_mark_last_busy(tas->dev); + pm_runtime_put_autosuspend(tas->dev); + + return ret; +} + +static int tas675x_set_acldg_trigger(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp =3D snd_kcontrol_chip(kcontrol); + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(comp); + unsigned int state, state34; + int ret; + + if (!ucontrol->value.integer.value[0]) + return 0; + + if (snd_soc_component_active(comp)) + return -EBUSY; + + ret =3D pm_runtime_resume_and_get(tas->dev); + if (ret < 0) + return ret; + + /* AC Load Diagnostics requires SLEEP state */ + ret =3D tas675x_set_state_all(tas, TAS675X_STATE_SLEEP_BOTH); + if (ret) { + dev_err(tas->dev, "AC LDG: Failed to set SLEEP state: %d\n", ret); + goto out; + } + + /* Start AC LDG on all 4 channels (0x0F) */ + ret =3D regmap_write(tas->regmap, TAS675X_AC_LDG_CTRL_REG, 0x0F); + if (ret) { + dev_err(tas->dev, "AC LDG: Failed to start: %d\n", ret); + goto out; + } + + dev_dbg(tas->dev, "AC LDG: Started\n"); + + /* Poll all channels for SLEEP state */ + ret =3D regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH1_CH= 2_REG, + state, (state =3D=3D TAS675X_STATE_SLEEP_BOTH), + TAS675X_POLL_INTERVAL_US, + TAS675X_AC_LDG_TIMEOUT_US); + if (ret) { + dev_err(tas->dev, + "AC LDG: CH1/CH2 timeout: %d (state=3D0x%02x [%s/%s])\n", + ret, state, tas675x_state_name(state), + tas675x_state_name(state >> 4)); + regmap_write(tas->regmap, TAS675X_AC_LDG_CTRL_REG, 0x00); + goto out; + } + + ret =3D regmap_read_poll_timeout(tas->regmap, TAS675X_STATE_REPORT_CH3_CH= 4_REG, + state34, (state34 =3D=3D TAS675X_STATE_SLEEP_BOTH), + TAS675X_POLL_INTERVAL_US, + TAS675X_AC_LDG_TIMEOUT_US); + if (ret) { + dev_err(tas->dev, + "AC LDG: CH3/CH4 timeout: %d (state=3D0x%02x [%s/%s])\n", + ret, state34, tas675x_state_name(state34), + tas675x_state_name(state34 >> 4)); + regmap_write(tas->regmap, TAS675X_AC_LDG_CTRL_REG, 0x00); + goto out; + } + + dev_dbg(tas->dev, "AC LDG: Completed successfully (CH1/2=3D0x%02x, CH3/4= =3D0x%02x)\n", + state, state34); + regmap_write(tas->regmap, TAS675X_AC_LDG_CTRL_REG, 0x00); + ret =3D 0; + +out: + pm_runtime_mark_last_busy(tas->dev); + pm_runtime_put_autosuspend(tas->dev); + + return ret; +} + +static int tas675x_rtldg_impedance_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count =3D 1; + uinfo->value.integer.min =3D 0; + uinfo->value.integer.max =3D 0xFFFF; + return 0; +} + +static int tas675x_get_rtldg_impedance(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp =3D snd_kcontrol_chip(kcontrol); + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(comp); + unsigned int msb_reg =3D (unsigned int)kcontrol->private_value; + unsigned int msb, lsb; + int ret; + + ret =3D regmap_read(tas->regmap, msb_reg, &msb); + if (ret) + return ret; + + ret =3D regmap_read(tas->regmap, msb_reg + 1, &lsb); + if (ret) + return ret; + + ucontrol->value.integer.value[0] =3D (msb << 8) | lsb; + return 0; +} + +static int tas675x_dc_resistance_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + /* 10-bit: 2-bit MSB + 8-bit LSB, 0.1 ohm/code, 0-102.3 ohm */ + uinfo->type =3D SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count =3D 1; + uinfo->value.integer.min =3D 0; + uinfo->value.integer.max =3D 1023; + return 0; +} + +static int tas675x_get_dc_resistance(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp =3D snd_kcontrol_chip(kcontrol); + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(comp); + unsigned int lsb_reg =3D (unsigned int)kcontrol->private_value; + unsigned int msb, lsb, shift; + int ret; + + ret =3D regmap_read(tas->regmap, TAS675X_DC_LDG_DCR_MSB_REG, &msb); + if (ret) + return ret; + + ret =3D regmap_read(tas->regmap, lsb_reg, &lsb); + if (ret) + return ret; + + /* 2-bit MSB: CH1=3D[7:6], CH2=3D[5:4], CH3=3D[3:2], CH4=3D[1:0] */ + shift =3D 6 - (lsb_reg - TAS675X_CH1_DC_LDG_DCR_LSB_REG) * 2; + msb =3D (msb >> shift) & 0x3; + + ucontrol->value.integer.value[0] =3D (msb << 8) | lsb; + return 0; +} + +/* Counterparts with read-only access */ +#define SOC_SINGLE_RO(xname, xreg, xshift, xmax) \ +{ .iface =3D SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name =3D xname, \ + .access =3D SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info =3D snd_soc_info_volsw, \ + .get =3D snd_soc_get_volsw, \ + .private_value =3D SOC_SINGLE_VALUE(xreg, xshift, 0, xmax, 0, 0) } +#define SOC_DC_RESIST_RO(xname, xlsb_reg) \ +{ .name =3D xname, \ + .iface =3D SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access =3D SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info =3D tas675x_dc_resistance_info, \ + .get =3D tas675x_get_dc_resistance, \ + .private_value =3D (xlsb_reg) } +#define SOC_RTLDG_IMP_RO(xname, xreg) \ +{ .name =3D xname, \ + .iface =3D SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access =3D SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info =3D tas675x_rtldg_impedance_info, \ + .get =3D tas675x_get_rtldg_impedance, \ + .private_value =3D (xreg) } + +#define SOC_DSP_THRESH_EXT(xname, xthresh) \ +{ .name =3D xname, \ + .iface =3D SNDRV_CTL_ELEM_IFACE_MIXER, \ + .info =3D tas675x_rtldg_thresh_info, \ + .get =3D tas675x_get_rtldg_thresh, \ + .put =3D tas675x_set_rtldg_thresh, \ + .private_value =3D (unsigned long)&(xthresh) } + +/* + * DAC digital volumes. From -103 to 0 dB in 0.5 dB steps, -103.5 dB means= mute. + * DAC analog gain. From -15.5 to 0 dB in 0.5 dB steps, no mute. + */ +static const DECLARE_TLV_DB_SCALE(tas675x_dig_vol_tlv, -10350, 50, 1); +static const DECLARE_TLV_DB_SCALE(tas675x_ana_gain_tlv, -1550, 50, 0); + +static const char * const tas675x_ss_texts[] =3D { + "Disabled", "Triangle", "Random", "Triangle and Random" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ss_enum, TAS675X_SS_CTRL_REG, 0, tas67= 5x_ss_texts); + +static const char * const tas675x_ss_tri_range_texts[] =3D { + "6.5%", "13.5%", "5%", "10%" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ss_tri_range_enum, + TAS675X_SS_RANGE_CTRL_REG, 0, + tas675x_ss_tri_range_texts); + +static const char * const tas675x_ss_rdm_range_texts[] =3D { + "0.83%", "2.50%", "5.83%", "12.50%", "25.83%" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ss_rdm_range_enum, + TAS675X_SS_RANGE_CTRL_REG, 4, + tas675x_ss_rdm_range_texts); + +static const char * const tas675x_ss_rdm_dwell_texts[] =3D { + "1/FSS to 2/FSS", "1/FSS to 4/FSS", "1/FSS to 8/FSS", "1/FSS to 15/FSS" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ss_rdm_dwell_enum, + TAS675X_SS_RANGE_CTRL_REG, 2, + tas675x_ss_rdm_dwell_texts); + +static const char * const tas675x_oc_limit_texts[] =3D { + "Level 4", "Level 3", "Level 2", "Level 1" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_oc_limit_enum, TAS675X_CURRENT_LIMIT_C= TRL_REG, + 0, tas675x_oc_limit_texts); + +static const char * const tas675x_otw_texts[] =3D { + "Disabled", ">95C", ">110C", ">125C", ">135C", ">145C", ">155C", ">165C" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ch1_otw_enum, + TAS675X_OTW_CTRL_CH1_CH2_REG, 4, + tas675x_otw_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch2_otw_enum, + TAS675X_OTW_CTRL_CH1_CH2_REG, 0, + tas675x_otw_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch3_otw_enum, + TAS675X_OTW_CTRL_CH3_CH4_REG, 4, + tas675x_otw_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch4_otw_enum, + TAS675X_OTW_CTRL_CH3_CH4_REG, 0, + tas675x_otw_texts); + +static const char * const tas675x_dc_ldg_sl_texts[] =3D { + "0.5 Ohm", "1 Ohm", "1.5 Ohm", "2 Ohm", "2.5 Ohm", + "3 Ohm", "3.5 Ohm", "4 Ohm", "4.5 Ohm", "5 Ohm" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ch1_dc_ldg_sl_enum, + TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 4, + tas675x_dc_ldg_sl_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch2_dc_ldg_sl_enum, + TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0, + tas675x_dc_ldg_sl_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch3_dc_ldg_sl_enum, + TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 4, + tas675x_dc_ldg_sl_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch4_dc_ldg_sl_enum, + TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0, + tas675x_dc_ldg_sl_texts); + +static const char * const tas675x_dc_slol_ramp_texts[] =3D { + "15 ms", "30 ms", "10 ms", "20 ms" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_dc_slol_ramp_enum, + TAS675X_DC_LDG_TIME_CTRL_REG, 6, + tas675x_dc_slol_ramp_texts); + +static const char * const tas675x_dc_slol_settling_texts[] =3D { + "10 ms", "5 ms", "20 ms", "15 ms" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_dc_slol_settling_enum, + TAS675X_DC_LDG_TIME_CTRL_REG, 4, + tas675x_dc_slol_settling_texts); + +static const char * const tas675x_dc_s2pg_ramp_texts[] =3D { + "5 ms", "2.5 ms", "10 ms", "15 ms" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_dc_s2pg_ramp_enum, + TAS675X_DC_LDG_TIME_CTRL_REG, 2, + tas675x_dc_s2pg_ramp_texts); + +static const char * const tas675x_dc_s2pg_settling_texts[] =3D { + "10 ms", "5 ms", "20 ms", "30 ms" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_dc_s2pg_settling_enum, + TAS675X_DC_LDG_TIME_CTRL_REG, 0, + tas675x_dc_s2pg_settling_texts); + +static const char * const tas675x_dsp_mode_texts[] =3D { + "Normal", "LLP", "FFLP" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_dsp_mode_enum, + TAS675X_LL_EN_REG, 0, + tas675x_dsp_mode_texts); + +static const char * const tas675x_ana_ramp_texts[] =3D { + "15us", "60us", "200us", "400us" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ana_ramp_enum, + TAS675X_ANALOG_GAIN_RAMP_CTRL_REG, 2, + tas675x_ana_ramp_texts); + +static const char * const tas675x_ramp_rate_texts[] =3D { + "4 FS", "16 FS", "32 FS", "Instant" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ramp_down_rate_enum, + TAS675X_DIG_VOL_RAMP_CTRL_REG, 6, + tas675x_ramp_rate_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ramp_up_rate_enum, + TAS675X_DIG_VOL_RAMP_CTRL_REG, 2, + tas675x_ramp_rate_texts); + +static const char * const tas675x_ramp_step_texts[] =3D { + "4dB", "2dB", "1dB", "0.5dB" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ramp_down_step_enum, + TAS675X_DIG_VOL_RAMP_CTRL_REG, 4, + tas675x_ramp_step_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ramp_up_step_enum, + TAS675X_DIG_VOL_RAMP_CTRL_REG, 0, + tas675x_ramp_step_texts); + +static const char * const tas675x_vol_combine_ch12_texts[] =3D { + "Independent", "CH2 follows CH1", "CH1 follows CH2" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_vol_combine_ch12_enum, + TAS675X_DIG_VOL_COMBINE_CTRL_REG, 0, + tas675x_vol_combine_ch12_texts); + +static const char * const tas675x_vol_combine_ch34_texts[] =3D { + "Independent", "CH4 follows CH3", "CH3 follows CH4" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_vol_combine_ch34_enum, + TAS675X_DIG_VOL_COMBINE_CTRL_REG, 2, + tas675x_vol_combine_ch34_texts); + +static const char * const tas675x_auto_mute_time_texts[] =3D { + "11.5ms", "53ms", "106.5ms", "266.5ms", + "535ms", "1065ms", "2665ms", "5330ms" +}; + +static SOC_ENUM_SINGLE_DECL(tas675x_ch1_mute_time_enum, + TAS675X_AUTO_MUTE_TIMING_CH1_CH2_REG, 4, + tas675x_auto_mute_time_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch2_mute_time_enum, + TAS675X_AUTO_MUTE_TIMING_CH1_CH2_REG, 0, + tas675x_auto_mute_time_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch3_mute_time_enum, + TAS675X_AUTO_MUTE_TIMING_CH3_CH4_REG, 4, + tas675x_auto_mute_time_texts); +static SOC_ENUM_SINGLE_DECL(tas675x_ch4_mute_time_enum, + TAS675X_AUTO_MUTE_TIMING_CH3_CH4_REG, 0, + tas675x_auto_mute_time_texts); + +/* + * ALSA Mixer Controls + * + * For detailed documentation of each control see: + * Documentation/sound/codecs/tas675x.rst + */ +static const struct snd_kcontrol_new tas675x_snd_controls[] =3D { + /* Volume & Gain Control */ + SOC_DOUBLE_R_TLV("Analog Playback Volume", TAS675X_ANALOG_GAIN_CH1_CH2_RE= G, + TAS675X_ANALOG_GAIN_CH3_CH4_REG, 1, 0x1F, 1, tas675x_ana_gain_tlv), + SOC_ENUM("Analog Gain Ramp Step", tas675x_ana_ramp_enum), + SOC_SINGLE_RANGE_TLV("CH1 Digital Playback Volume", + TAS675X_DIG_VOL_CH1_REG, 0, 0x30, 0xFF, 1, + tas675x_dig_vol_tlv), + SOC_SINGLE_RANGE_TLV("CH2 Digital Playback Volume", + TAS675X_DIG_VOL_CH2_REG, 0, 0x30, 0xFF, 1, + tas675x_dig_vol_tlv), + SOC_SINGLE_RANGE_TLV("CH3 Digital Playback Volume", + TAS675X_DIG_VOL_CH3_REG, 0, 0x30, 0xFF, 1, + tas675x_dig_vol_tlv), + SOC_SINGLE_RANGE_TLV("CH4 Digital Playback Volume", + TAS675X_DIG_VOL_CH4_REG, 0, 0x30, 0xFF, 1, + tas675x_dig_vol_tlv), + SOC_ENUM("Volume Ramp Down Rate", tas675x_ramp_down_rate_enum), + SOC_ENUM("Volume Ramp Down Step", tas675x_ramp_down_step_enum), + SOC_ENUM("Volume Ramp Up Rate", tas675x_ramp_up_rate_enum), + SOC_ENUM("Volume Ramp Up Step", tas675x_ramp_up_step_enum), + SOC_ENUM("CH1/2 Volume Combine", tas675x_vol_combine_ch12_enum), + SOC_ENUM("CH3/4 Volume Combine", tas675x_vol_combine_ch34_enum), + + /* Auto Mute & Silence Detection */ + SOC_SINGLE("CH1 Auto Mute Switch", TAS675X_AUTO_MUTE_EN_REG, 0, 1, 0), + SOC_SINGLE("CH2 Auto Mute Switch", TAS675X_AUTO_MUTE_EN_REG, 1, 1, 0), + SOC_SINGLE("CH3 Auto Mute Switch", TAS675X_AUTO_MUTE_EN_REG, 2, 1, 0), + SOC_SINGLE("CH4 Auto Mute Switch", TAS675X_AUTO_MUTE_EN_REG, 3, 1, 0), + SOC_SINGLE("Auto Mute Combine Switch", TAS675X_AUTO_MUTE_EN_REG, 4, 1, 0), + SOC_ENUM("CH1 Auto Mute Time", tas675x_ch1_mute_time_enum), + SOC_ENUM("CH2 Auto Mute Time", tas675x_ch2_mute_time_enum), + SOC_ENUM("CH3 Auto Mute Time", tas675x_ch3_mute_time_enum), + SOC_ENUM("CH4 Auto Mute Time", tas675x_ch4_mute_time_enum), + + /* Clock & EMI Management */ + SOC_ENUM("Spread Spectrum Mode", tas675x_ss_enum), + SOC_ENUM("SS Triangle Range", tas675x_ss_tri_range_enum), + SOC_ENUM("SS Random Range", tas675x_ss_rdm_range_enum), + SOC_ENUM("SS Random Dwell Range", tas675x_ss_rdm_dwell_enum), + SOC_SINGLE("SS Triangle Dwell Min", TAS675X_SS_DWELL_CTRL_REG, 4, 15, 0), + SOC_SINGLE("SS Triangle Dwell Max", TAS675X_SS_DWELL_CTRL_REG, 0, 15, 0), + + /* Hardware Protection */ + SOC_SINGLE("OTSD Auto Recovery Switch", TAS675X_OTSD_RECOVERY_EN_REG, 1, = 1, 0), + SOC_ENUM("Overcurrent Limit Level", tas675x_oc_limit_enum), + SOC_ENUM("CH1 OTW Threshold", tas675x_ch1_otw_enum), + SOC_ENUM("CH2 OTW Threshold", tas675x_ch2_otw_enum), + SOC_ENUM("CH3 OTW Threshold", tas675x_ch3_otw_enum), + SOC_ENUM("CH4 OTW Threshold", tas675x_ch4_otw_enum), + + /* DSP Signal Path & Mode */ + SOC_ENUM("DSP Signal Path Mode", tas675x_dsp_mode_enum), + + /* DC Load Diagnostics */ + { + .iface =3D SNDRV_CTL_ELEM_IFACE_MIXER, + .name =3D "DC LDG Trigger", + .access =3D SNDRV_CTL_ELEM_ACCESS_WRITE, + .info =3D snd_ctl_boolean_mono_info, + .put =3D tas675x_set_dcldg_trigger, + }, + SOC_SINGLE("DC LDG Auto Diagnostics Switch", TAS675X_DC_LDG_CTRL_REG, 0, = 1, 1), + SOC_SINGLE("CH1 LO LDG Switch", TAS675X_DC_LDG_LO_CTRL_REG, 3, 1, 0), + SOC_SINGLE("CH2 LO LDG Switch", TAS675X_DC_LDG_LO_CTRL_REG, 2, 1, 0), + SOC_SINGLE("CH3 LO LDG Switch", TAS675X_DC_LDG_LO_CTRL_REG, 1, 1, 0), + SOC_SINGLE("CH4 LO LDG Switch", TAS675X_DC_LDG_LO_CTRL_REG, 0, 1, 0), + SOC_ENUM("DC LDG SLOL Ramp Time", tas675x_dc_slol_ramp_enum), + SOC_ENUM("DC LDG SLOL Settling Time", tas675x_dc_slol_settling_enum), + SOC_ENUM("DC LDG S2PG Ramp Time", tas675x_dc_s2pg_ramp_enum), + SOC_ENUM("DC LDG S2PG Settling Time", tas675x_dc_s2pg_settling_enum), + SOC_ENUM("CH1 DC LDG SL Threshold", tas675x_ch1_dc_ldg_sl_enum), + SOC_ENUM("CH2 DC LDG SL Threshold", tas675x_ch2_dc_ldg_sl_enum), + SOC_ENUM("CH3 DC LDG SL Threshold", tas675x_ch3_dc_ldg_sl_enum), + SOC_ENUM("CH4 DC LDG SL Threshold", tas675x_ch4_dc_ldg_sl_enum), + SOC_SINGLE_RO("DC LDG Result", TAS675X_DC_LDG_RESULT_REG, 0, 0xFF), + SOC_SINGLE_RO("CH1 DC LDG Report", TAS675X_DC_LDG_REPORT_CH1_CH2_REG, 4, = 0x0F), + SOC_SINGLE_RO("CH2 DC LDG Report", TAS675X_DC_LDG_REPORT_CH1_CH2_REG, 0, = 0x0F), + SOC_SINGLE_RO("CH3 DC LDG Report", TAS675X_DC_LDG_REPORT_CH3_CH4_REG, 4, = 0x0F), + SOC_SINGLE_RO("CH4 DC LDG Report", TAS675X_DC_LDG_REPORT_CH3_CH4_REG, 0, = 0x0F), + SOC_SINGLE_RO("CH1 LO LDG Report", TAS675X_DC_LDG_RESULT_REG, 7, 1), + SOC_SINGLE_RO("CH2 LO LDG Report", TAS675X_DC_LDG_RESULT_REG, 6, 1), + SOC_SINGLE_RO("CH3 LO LDG Report", TAS675X_DC_LDG_RESULT_REG, 5, 1), + SOC_SINGLE_RO("CH4 LO LDG Report", TAS675X_DC_LDG_RESULT_REG, 4, 1), + SOC_DC_RESIST_RO("CH1 DC Resistance", TAS675X_CH1_DC_LDG_DCR_LSB_REG), + SOC_DC_RESIST_RO("CH2 DC Resistance", TAS675X_CH2_DC_LDG_DCR_LSB_REG), + SOC_DC_RESIST_RO("CH3 DC Resistance", TAS675X_CH3_DC_LDG_DCR_LSB_REG), + SOC_DC_RESIST_RO("CH4 DC Resistance", TAS675X_CH4_DC_LDG_DCR_LSB_REG), + + /* AC Load Diagnostics */ + { + .iface =3D SNDRV_CTL_ELEM_IFACE_MIXER, + .name =3D "AC LDG Trigger", + .access =3D SNDRV_CTL_ELEM_ACCESS_WRITE, + .info =3D snd_ctl_boolean_mono_info, + .put =3D tas675x_set_acldg_trigger, + }, + SOC_SINGLE("AC DIAG GAIN", TAS675X_AC_LDG_CTRL_REG, 4, 1, 0), + SOC_SINGLE("AC LDG Test Frequency", TAS675X_AC_LDG_FREQ_CTRL_REG, 0, 0xFF= , 0), + SOC_SINGLE_RO("CH1 AC LDG Real", TAS675X_AC_LDG_REPORT_CH1_R_REG, 0, 0xFF= ), + SOC_SINGLE_RO("CH1 AC LDG Imag", TAS675X_AC_LDG_REPORT_CH1_I_REG, 0, 0xFF= ), + SOC_SINGLE_RO("CH2 AC LDG Real", TAS675X_AC_LDG_REPORT_CH2_R_REG, 0, 0xFF= ), + SOC_SINGLE_RO("CH2 AC LDG Imag", TAS675X_AC_LDG_REPORT_CH2_I_REG, 0, 0xFF= ), + SOC_SINGLE_RO("CH3 AC LDG Real", TAS675X_AC_LDG_REPORT_CH3_R_REG, 0, 0xFF= ), + SOC_SINGLE_RO("CH3 AC LDG Imag", TAS675X_AC_LDG_REPORT_CH3_I_REG, 0, 0xFF= ), + SOC_SINGLE_RO("CH4 AC LDG Real", TAS675X_AC_LDG_REPORT_CH4_R_REG, 0, 0xFF= ), + SOC_SINGLE_RO("CH4 AC LDG Imag", TAS675X_AC_LDG_REPORT_CH4_I_REG, 0, 0xFF= ), + + /* Temperature and Voltage Monitoring */ + SOC_SINGLE_RO("PVDD Sense", TAS675X_PVDD_SENSE_REG, 0, 0xFF), + SOC_SINGLE_RO("Global Temperature", TAS675X_TEMP_GLOBAL_REG, 0, 0xFF), + SOC_SINGLE_RO("CH1 Temperature Range", TAS675X_TEMP_CH1_CH2_REG, 6, 3), + SOC_SINGLE_RO("CH2 Temperature Range", TAS675X_TEMP_CH1_CH2_REG, 4, 3), + SOC_SINGLE_RO("CH3 Temperature Range", TAS675X_TEMP_CH3_CH4_REG, 2, 3), + SOC_SINGLE_RO("CH4 Temperature Range", TAS675X_TEMP_CH3_CH4_REG, 0, 3), + + /* Speaker Protection & Detection */ + SOC_SINGLE("Tweeter Detection Switch", TAS675X_TWEETER_DETECT_CTRL_REG, 0= , 1, 1), + SOC_SINGLE("Tweeter Detect Threshold", TAS675X_TWEETER_DETECT_THRESH_REG,= 0, 0xFF, 0), + SOC_SINGLE_RO("CH1 Tweeter Detect Report", TAS675X_TWEETER_REPORT_REG, 3,= 1), + SOC_SINGLE_RO("CH2 Tweeter Detect Report", TAS675X_TWEETER_REPORT_REG, 2,= 1), + SOC_SINGLE_RO("CH3 Tweeter Detect Report", TAS675X_TWEETER_REPORT_REG, 1,= 1), + SOC_SINGLE_RO("CH4 Tweeter Detect Report", TAS675X_TWEETER_REPORT_REG, 0,= 1), + + /* + * Unavailable in LLP, available in Normal & FFLP + */ + SOC_SINGLE("Thermal Foldback Switch", TAS675X_DSP_CTRL_REG, 0, 1, 0), + SOC_SINGLE("PVDD Foldback Switch", TAS675X_DSP_CTRL_REG, 4, 1, 0), + SOC_SINGLE("DC Blocker Bypass Switch", TAS675X_DC_BLOCK_BYP_REG, 0, 1, 0), + SOC_SINGLE("Clip Detect Switch", TAS675X_CLIP_DETECT_CTRL_REG, 6, 1, 0), + SOC_SINGLE("Audio SDOUT Switch", TAS675X_DSP_CTRL_REG, 5, 1, 0), + + /* + * Unavailable in both FFLP and LLP, Normal mode only + */ + + /* Real-Time Load Diagnostics */ + SOC_SINGLE("CH1 RTLDG Switch", TAS675X_RTLDG_EN_REG, 3, 1, 0), + SOC_SINGLE("CH2 RTLDG Switch", TAS675X_RTLDG_EN_REG, 2, 1, 0), + SOC_SINGLE("CH3 RTLDG Switch", TAS675X_RTLDG_EN_REG, 1, 1, 0), + SOC_SINGLE("CH4 RTLDG Switch", TAS675X_RTLDG_EN_REG, 0, 1, 0), + SOC_SINGLE("RTLDG Clip Mask Switch", TAS675X_RTLDG_EN_REG, 4, 1, 0), + SOC_SINGLE("ISENSE Calibration Switch", TAS675X_ISENSE_CAL_REG, 3, 1, 0), + SOC_DSP_THRESH_EXT("RTLDG Open Load Threshold", + tas675x_dsp_defaults[TAS675X_DSP_PARAM_ID_OL_THRESH]), + SOC_DSP_THRESH_EXT("RTLDG Short Load Threshold", + tas675x_dsp_defaults[TAS675X_DSP_PARAM_ID_SL_THRESH]), + SOC_RTLDG_IMP_RO("CH1 RTLDG Impedance", TAS675X_CH1_RTLDG_IMP_MSB_REG), + SOC_RTLDG_IMP_RO("CH2 RTLDG Impedance", TAS675X_CH2_RTLDG_IMP_MSB_REG), + SOC_RTLDG_IMP_RO("CH3 RTLDG Impedance", TAS675X_CH3_RTLDG_IMP_MSB_REG), + SOC_RTLDG_IMP_RO("CH4 RTLDG Impedance", TAS675X_CH4_RTLDG_IMP_MSB_REG), + SOC_SINGLE_RO("RTLDG Fault Latched", TAS675X_RTLDG_OL_SL_FAULT_LATCHED_RE= G, 0, 0xFF), +}; + +static const struct snd_kcontrol_new tas675x_audio_path_switch =3D + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 1); + +static const struct snd_kcontrol_new tas675x_anc_path_switch =3D + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 1); + +static int tas675x_dapm_sleep_event(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component =3D snd_soc_dapm_to_component(widget-= >dapm); + int ret =3D 0; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + ret =3D pm_runtime_resume_and_get(component->dev); + break; + case SND_SOC_DAPM_PRE_PMD: + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + break; + } + return ret < 0 ? ret : 0; +} + +static const struct snd_soc_dapm_widget tas675x_dapm_widgets[] =3D { + SND_SOC_DAPM_SUPPLY("Analog Core", SND_SOC_NOPM, 0, 0, + tas675x_dapm_sleep_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("SDOUT Vpredict", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("SDOUT Isense", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_DAC("Audio DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("ANC DAC", "ANC Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("Feedback ADC", "Feedback Capture", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SWITCH("Audio Path", SND_SOC_NOPM, 0, 0, + &tas675x_audio_path_switch), + SND_SOC_DAPM_SWITCH("ANC Path", SND_SOC_NOPM, 0, 0, + &tas675x_anc_path_switch), + + /* + * Even though all channels are coupled in terms of power control, + * use logical outputs for each channel to allow independent routing + * and DAPM controls if needed. + */ + SND_SOC_DAPM_OUTPUT("OUT_CH1"), + SND_SOC_DAPM_OUTPUT("OUT_CH2"), + SND_SOC_DAPM_OUTPUT("OUT_CH3"), + SND_SOC_DAPM_OUTPUT("OUT_CH4"), + SND_SOC_DAPM_INPUT("SPEAKER_LOAD"), +}; + +static const struct snd_soc_dapm_route tas675x_audio_map[] =3D { + { "Audio DAC", NULL, "Analog Core" }, + { "Audio Path", "Switch", "Audio DAC" }, + { "OUT_CH1", NULL, "Audio Path" }, + { "OUT_CH2", NULL, "Audio Path" }, + { "OUT_CH3", NULL, "Audio Path" }, + { "OUT_CH4", NULL, "Audio Path" }, + + { "ANC DAC", NULL, "Analog Core" }, + { "ANC Path", "Switch", "ANC DAC" }, + { "OUT_CH1", NULL, "ANC Path" }, + { "OUT_CH2", NULL, "ANC Path" }, + { "OUT_CH3", NULL, "ANC Path" }, + { "OUT_CH4", NULL, "ANC Path" }, + + { "Feedback ADC", NULL, "Analog Core" }, + { "Feedback ADC", NULL, "SDOUT Vpredict" }, + { "Feedback ADC", NULL, "SDOUT Isense" }, + { "Feedback ADC", NULL, "SPEAKER_LOAD" }, +}; + +static void tas675x_program_slot_offsets(struct tas675x_priv *tas, + int dai_id, int slot_width) +{ + int offset =3D 0; + + switch (dai_id) { + case 0: + /* Standard Audio on SDIN */ + if (tas->audio_slot >=3D 0) + offset =3D tas->audio_slot * slot_width; + else if (tas->tx_mask) + offset =3D __ffs(tas->tx_mask) * slot_width; + else + return; + offset +=3D tas->bclk_offset; + regmap_update_bits(tas->regmap, TAS675X_SDIN_OFFSET_MSB_REG, + TAS675X_SDIN_AUDIO_OFF_MSB_MASK, + FIELD_PREP(TAS675X_SDIN_AUDIO_OFF_MSB_MASK, offset >> 8)); + regmap_write(tas->regmap, TAS675X_SDIN_AUDIO_OFFSET_REG, + offset & 0xFF); + break; + case 1: + /* + * Low-Latency Playback on SDIN, **only** enabled in LLP mode + * and to be mixed with main audio before output amplification + * to achieve ANC/RNC. + */ + if (tas->llp_slot >=3D 0) + offset =3D tas->llp_slot * slot_width; + else if (tas->tx_mask) + offset =3D __ffs(tas->tx_mask) * slot_width; + else + return; + offset +=3D tas->bclk_offset; + regmap_update_bits(tas->regmap, TAS675X_SDIN_OFFSET_MSB_REG, + TAS675X_SDIN_LL_OFF_MSB_MASK, + FIELD_PREP(TAS675X_SDIN_LL_OFF_MSB_MASK, offset >> 8)); + regmap_write(tas->regmap, TAS675X_SDIN_LL_OFFSET_REG, + offset & 0xFF); + break; + case 2: + /* SDOUT Data Output (Vpredict + Isense feedback) */ + if (!tas->slot_width) + break; + if (tas->vpredict_slot >=3D 0) { + offset =3D tas->vpredict_slot * slot_width; + offset +=3D tas->bclk_offset; + regmap_update_bits(tas->regmap, TAS675X_SDOUT_OFFSET_MSB_REG, + TAS675X_SDOUT_VP_OFF_MSB_MASK, + FIELD_PREP(TAS675X_SDOUT_VP_OFF_MSB_MASK, offset >> 8)); + regmap_write(tas->regmap, TAS675X_VPREDICT_OFFSET_REG, + offset & 0xFF); + } + if (tas->isense_slot >=3D 0) { + offset =3D tas->isense_slot * slot_width; + offset +=3D tas->bclk_offset; + regmap_update_bits(tas->regmap, TAS675X_SDOUT_OFFSET_MSB_REG, + TAS675X_SDOUT_IS_OFF_MSB_MASK, + FIELD_PREP(TAS675X_SDOUT_IS_OFF_MSB_MASK, offset >> 8)); + regmap_write(tas->regmap, TAS675X_ISENSE_OFFSET_REG, + offset & 0xFF); + } + break; + } + + if (offset > 511) + dev_warn(tas->dev, + "DAI %d slot offset %d exceeds 511 SCLK limit\n", + dai_id, offset); +} + +static int tas675x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component =3D dai->component; + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(component); + unsigned int rate =3D params_rate(params); + u8 word_length; + + /* + * Single clock domain: SDIN and SDOUT share one SCLK/FSYNC pair, + * so all active DAIs must use the same sample rate. + */ + if ((tas->active_playback_dais || tas->active_capture_dais) && + tas->rate && tas->rate !=3D rate) { + dev_err(component->dev, + "Rate %u conflicts with active rate %u\n", + rate, tas->rate); + return -EINVAL; + } + + switch (params_width(params)) { + case 16: + word_length =3D TAS675X_WL_16BIT; + break; + case 20: + word_length =3D TAS675X_WL_20BIT; + break; + case 24: + word_length =3D TAS675X_WL_24BIT; + break; + case 32: + word_length =3D TAS675X_WL_32BIT; + break; + default: + return -EINVAL; + } + + if (substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK) { + /* + * RTLDG is not supported above 96kHz. Auto-disable to + * prevent DSP overload and restore when rate drops back. + */ + if (params_rate(params) > 96000) { + unsigned int val; + + regmap_read(component->regmap, TAS675X_RTLDG_EN_REG, + &val); + if (val & TAS675X_RTLDG_CH_EN_MASK) { + tas->saved_rtldg_en =3D val; + dev_dbg(component->dev, + "Sample rate %dHz > 96kHz: Auto-disabling RTLDG\n", + params_rate(params)); + regmap_update_bits(component->regmap, + TAS675X_RTLDG_EN_REG, + TAS675X_RTLDG_CH_EN_MASK, + 0x00); + } + } else if (tas->saved_rtldg_en) { + unsigned int cur; + + /* + * Respect overrides and only restore if RTLDG is still auto-disabled + */ + regmap_read(component->regmap, TAS675X_RTLDG_EN_REG, + &cur); + if (!(cur & TAS675X_RTLDG_CH_EN_MASK)) { + dev_dbg(component->dev, + "Restoring RTLDG config after high-rate stream\n"); + regmap_update_bits(component->regmap, + TAS675X_RTLDG_EN_REG, + TAS675X_RTLDG_CH_EN_MASK, + TAS675X_RTLDG_CH_EN_MASK & + tas->saved_rtldg_en); + } + tas->saved_rtldg_en =3D 0; + } + + /* Set SDIN word length (audio path + low-latency path) */ + regmap_update_bits(component->regmap, TAS675X_SDIN_CTRL_REG, + TAS675X_SDIN_WL_MASK, + FIELD_PREP(TAS675X_SDIN_AUDIO_WL_MASK, word_length) | + FIELD_PREP(TAS675X_SDIN_LL_WL_MASK, word_length)); + } else { + /* Set SDOUT word length (VPREDICT + ISENSE) for capture */ + regmap_update_bits(component->regmap, TAS675X_SDOUT_CTRL_REG, + TAS675X_SDOUT_WL_MASK, + FIELD_PREP(TAS675X_SDOUT_VP_WL_MASK, word_length) | + FIELD_PREP(TAS675X_SDOUT_IS_WL_MASK, word_length)); + } + + tas675x_program_slot_offsets(tas, dai->id, + tas->slot_width ?: params_width(params)); + + tas->rate =3D rate; + + return 0; +} + +static int tas675x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component =3D dai->component; + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(component); + bool tdm_mode =3D false, i2s_mode =3D false; + + /* Enforce Clocking Direction (Codec is strictly a consumer) */ + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_BC_FC: + break; + default: + dev_err(component->dev, "Unsupported clock provider format\n"); + return -EINVAL; + } + + /* SCLK polarity: NB_NF or IB_NF only (no FSYNC inversion support) */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + regmap_update_bits(component->regmap, TAS675X_SCLK_INV_CTRL_REG, + TAS675X_SCLK_INV_MASK, 0x00); + break; + case SND_SOC_DAIFMT_IB_NF: + regmap_update_bits(component->regmap, TAS675X_SCLK_INV_CTRL_REG, + TAS675X_SCLK_INV_MASK, TAS675X_SCLK_INV_MASK); + break; + default: + dev_err(component->dev, "Unsupported clock inversion\n"); + return -EINVAL; + } + + /* Configure Audio Format and TDM Enable */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + i2s_mode =3D true; + tas->bclk_offset =3D 0; + regmap_update_bits(component->regmap, TAS675X_AUDIO_IF_CTRL_REG, + TAS675X_TDM_EN_BIT | TAS675X_SAP_FMT_MASK | + TAS675X_FS_PULSE_MASK, + TAS675X_SAP_FMT_I2S); + regmap_update_bits(component->regmap, TAS675X_SDOUT_CTRL_REG, + TAS675X_SDOUT_SELECT_MASK, + TAS675X_SDOUT_SELECT_NON_TDM); + break; + case SND_SOC_DAIFMT_RIGHT_J: + tas->bclk_offset =3D 0; + regmap_update_bits(component->regmap, TAS675X_AUDIO_IF_CTRL_REG, + TAS675X_TDM_EN_BIT | TAS675X_SAP_FMT_MASK | + TAS675X_FS_PULSE_MASK, + TAS675X_SAP_FMT_RIGHT_J); + regmap_update_bits(component->regmap, TAS675X_SDOUT_CTRL_REG, + TAS675X_SDOUT_SELECT_MASK, + TAS675X_SDOUT_SELECT_NON_TDM); + break; + case SND_SOC_DAIFMT_LEFT_J: + tas->bclk_offset =3D 0; + regmap_update_bits(component->regmap, TAS675X_AUDIO_IF_CTRL_REG, + TAS675X_TDM_EN_BIT | TAS675X_SAP_FMT_MASK | + TAS675X_FS_PULSE_MASK, + TAS675X_SAP_FMT_LEFT_J); + regmap_update_bits(component->regmap, TAS675X_SDOUT_CTRL_REG, + TAS675X_SDOUT_SELECT_MASK, + TAS675X_SDOUT_SELECT_NON_TDM); + break; + case SND_SOC_DAIFMT_DSP_A: + tdm_mode =3D true; + tas->bclk_offset =3D 1; + regmap_update_bits(component->regmap, TAS675X_AUDIO_IF_CTRL_REG, + TAS675X_TDM_EN_BIT | TAS675X_SAP_FMT_MASK | + TAS675X_FS_PULSE_MASK, + TAS675X_TDM_EN_BIT | TAS675X_SAP_FMT_TDM | + TAS675X_FS_PULSE_SHORT); + regmap_update_bits(component->regmap, TAS675X_SDOUT_CTRL_REG, + TAS675X_SDOUT_SELECT_MASK, + TAS675X_SDOUT_SELECT_TDM_SDOUT1); + break; + case SND_SOC_DAIFMT_DSP_B: + tdm_mode =3D true; + tas->bclk_offset =3D 0; + regmap_update_bits(component->regmap, TAS675X_AUDIO_IF_CTRL_REG, + TAS675X_TDM_EN_BIT | TAS675X_SAP_FMT_MASK | + TAS675X_FS_PULSE_MASK, + TAS675X_TDM_EN_BIT | TAS675X_SAP_FMT_TDM | + TAS675X_FS_PULSE_SHORT); + regmap_update_bits(component->regmap, TAS675X_SDOUT_CTRL_REG, + TAS675X_SDOUT_SELECT_MASK, + TAS675X_SDOUT_SELECT_TDM_SDOUT1); + break; + default: + dev_err(component->dev, "Unsupported DAI format\n"); + return -EINVAL; + } + + /* Setup Vpredict and Isense outputs */ + if (dai->id =3D=3D 2) { + unsigned int sdout_en =3D 0; + + if (tdm_mode) { + /* TDM: Vpredict and Isense may coexist on separate slots */ + if (tas->vpredict_slot >=3D 0) + sdout_en |=3D TAS675X_SDOUT_EN_VPREDICT; + if (tas->isense_slot >=3D 0) + sdout_en |=3D TAS675X_SDOUT_EN_ISENSE; + regmap_update_bits(component->regmap, + TAS675X_SDOUT_EN_REG, + TAS675X_SDOUT_EN_VPREDICT | + TAS675X_SDOUT_EN_ISENSE, + sdout_en); + if (tas->vpredict_slot >=3D 0 && tas->isense_slot >=3D 0 && + abs(tas->vpredict_slot - tas->isense_slot) < 4) + dev_warn(component->dev, + "ti,vpredict-slot-no and ti,isense-slot-no overlaps (each occupies 4= consecutive slots)\n"); + } else if (i2s_mode) { + /* I2S: only one source at a time; Vpredict takes priority */ + if (tas->vpredict_slot >=3D 0) + sdout_en =3D TAS675X_SDOUT_NON_TDM_SEL_VPREDICT | + TAS675X_SDOUT_EN_NON_TDM_ALL; + else if (tas->isense_slot >=3D 0) + sdout_en =3D TAS675X_SDOUT_NON_TDM_SEL_ISENSE | + TAS675X_SDOUT_EN_NON_TDM_ALL; + regmap_update_bits(component->regmap, + TAS675X_SDOUT_EN_REG, + TAS675X_SDOUT_NON_TDM_SEL_MASK | + TAS675X_SDOUT_EN_NON_TDM_ALL, + sdout_en); + if (sdout_en && + tas->gpio1_func !=3D TAS675X_GPIO_SEL_SDOUT2 && + tas->gpio2_func !=3D TAS675X_GPIO_SEL_SDOUT2) + dev_warn(component->dev, + "sdout enabled in I2S mode but no GPIO configured as SDOUT2; Ch3/Ch4= will be absent\n"); + } + } + + return 0; +} + +static int tas675x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_m= ask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(dai->component= ); + + if (slots =3D=3D 0) { + tas->slot_width =3D 0; + tas->tx_mask =3D 0; + return 0; + } + + /* No rx_mask as hardware does not support channel muxing for capture */ + tas->slot_width =3D slot_width; + tas->tx_mask =3D tx_mask; + return 0; +} + +static int tas675x_mute_stream(struct snd_soc_dai *dai, int mute, int dire= ction) +{ + struct snd_soc_component *component =3D dai->component; + struct tas675x_priv *tas =3D snd_soc_component_get_drvdata(component); + unsigned int discard; + int ret; + + if (direction =3D=3D SNDRV_PCM_STREAM_CAPTURE) { + if (mute) + clear_bit(dai->id, &tas->active_capture_dais); + else + set_bit(dai->id, &tas->active_capture_dais); + return 0; + } + + /* + * Track which playback DAIs are active. + * The TAS675x has two playback DAIs (main audio and LLP). + * Only transition to Hi-Z when ALL are muted. + */ + if (mute) + clear_bit(dai->id, &tas->active_playback_dais); + else + set_bit(dai->id, &tas->active_playback_dais); + + /* Last playback stream */ + if (mute && !tas->active_playback_dais) { + ret =3D tas675x_set_state_all(tas, TAS675X_STATE_SLEEP_BOTH); + regmap_read(tas->regmap, TAS675X_CLK_FAULT_LATCHED_REG, &discard); + return ret; + } + + return tas675x_set_state_all(tas, + tas->active_playback_dais ? + TAS675X_STATE_PLAY_BOTH : + TAS675X_STATE_SLEEP_BOTH); +} + +static const struct snd_soc_dai_ops tas675x_dai_ops =3D { + .hw_params =3D tas675x_hw_params, + .set_fmt =3D tas675x_set_dai_fmt, + .set_tdm_slot =3D tas675x_set_tdm_slot, + .mute_stream =3D tas675x_mute_stream, +}; + +static struct snd_soc_dai_driver tas675x_dais[] =3D { + { + .name =3D "tas675x-audio", + .id =3D 0, + .playback =3D { + .stream_name =3D "Playback", + .channels_min =3D 2, + .channels_max =3D 4, + .rates =3D SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000, + .formats =3D SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops =3D &tas675x_dai_ops, + }, + /* Only available when Low Latency Path (LLP) is enabled */ + { + .name =3D "tas675x-anc", + .id =3D 1, + .playback =3D { + .stream_name =3D "ANC Playback", + .channels_min =3D 2, + .channels_max =3D 4, + .rates =3D SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000, + .formats =3D SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops =3D &tas675x_dai_ops, + }, + { + .name =3D "tas675x-feedback", + .id =3D 2, + .capture =3D { + .stream_name =3D "Feedback Capture", + .channels_min =3D 2, + .channels_max =3D 8, + .rates =3D SNDRV_PCM_RATE_48000, + .formats =3D SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops =3D &tas675x_dai_ops, + } +}; + +/** + * Hardware power sequencing + * Handles regulator enable and GPIO deassertion. + * The device is not be I2C-accessible until boot wait completes. + */ +static int tas675x_hw_enable(struct tas675x_priv *tas) +{ + int ret; + + ret =3D regulator_bulk_enable(ARRAY_SIZE(tas->supplies), tas->supplies); + if (ret) { + dev_err(tas->dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + if (!IS_ERR(tas->vbat)) { + ret =3D regulator_enable(tas->vbat); + if (ret) { + dev_err(tas->dev, "Failed to enable vbat: %d\n", ret); + regulator_bulk_disable(ARRAY_SIZE(tas->supplies), tas->supplies); + return ret; + } + } + + if (tas->pd_gpio && tas->stby_gpio) { + /* + * Independent Pin Control + * Deassert PD first to boot digital, then STBY for analog. + */ + /* Min 4ms digital boot wait */ + gpiod_set_value_cansleep(tas->pd_gpio, 0); + usleep_range(4000, 5000); + + /* ~2ms analog stabilization */ + gpiod_set_value_cansleep(tas->stby_gpio, 0); + usleep_range(2000, 3000); + } else if (tas->pd_gpio) { + /* + * Simultaneous Pin Release + * STBY tied to PD or hardwired HIGH. + */ + /* 6ms wait for simultaneous release transition */ + gpiod_set_value_cansleep(tas->pd_gpio, 0); + usleep_range(6000, 7000); + } else { + /* + * PD hardwired, device in DEEP_SLEEP. + * Digital core already booted, I2C active. Deassert STBY + * to bring up the analog output stage. + */ + /* ~2ms analog stabilization */ + gpiod_set_value_cansleep(tas->stby_gpio, 0); + usleep_range(2000, 3000); + } + + return 0; +} + +static void tas675x_hw_disable(struct tas675x_priv *tas) +{ + if (tas->stby_gpio) + gpiod_set_value_cansleep(tas->stby_gpio, 1); + + if (tas->pd_gpio) + gpiod_set_value_cansleep(tas->pd_gpio, 1); + + /* + * Hold PD/STBY asserted for at least 10ms + * before removing PVDD, VBAT or DVDD. + */ + usleep_range(10000, 11000); + + if (!IS_ERR(tas->vbat)) + regulator_disable(tas->vbat); + + regulator_bulk_disable(ARRAY_SIZE(tas->supplies), tas->supplies); +} + +/** + * Device start-up defaults + * Must be called after tas675x_hw_enable() and after regcache is enabled. + */ +static int tas675x_init_device(struct tas675x_priv *tas) +{ + struct regmap *regmap =3D tas->regmap; + unsigned int val; + int ret, i; + + /* Clear POR fault flag to prevent IRQ storm */ + regmap_read(regmap, TAS675X_POWER_FAULT_LATCHED_REG, &val); + + /* Bypass DC Load Diagnostics for fast boot */ + if (tas->fast_boot) + regmap_update_bits(regmap, TAS675X_DC_LDG_CTRL_REG, + TAS675X_LDG_ABORT_BIT | TAS675X_LDG_BYPASS_BIT, + TAS675X_LDG_ABORT_BIT | TAS675X_LDG_BYPASS_BIT); + + tas675x_select_book(regmap, TAS675X_BOOK_DEFAULT); + + /* Enter setup mode */ + ret =3D regmap_write(regmap, TAS675X_SETUP_REG1, TAS675X_SETUP_ENTER_VAL1= ); + if (ret) + goto err; + ret =3D regmap_write(regmap, TAS675X_SETUP_REG2, TAS675X_SETUP_ENTER_VAL2= ); + if (ret) + goto err; + + /* Set all channels to Sleep (required before Page 1 config) */ + tas675x_set_state_all(tas, TAS675X_STATE_SLEEP_BOTH); + + /* Set DAC clock per TRM startup script */ + regmap_write(regmap, TAS675X_DAC_CLK_REG, 0x00); + + /* + * Switch to Page 1 for safety-critical OC/CBC configuration, + * while bypassing regcache. (Page 1 not accessible post setup) + */ + regcache_cache_bypass(regmap, true); + ret =3D regmap_multi_reg_write(regmap, tas675x_page1_init, + ARRAY_SIZE(tas675x_page1_init)); + regcache_cache_bypass(regmap, false); + if (ret) + goto err_setup; + + /* Resync regmap's cached page selector */ + regmap_write(regmap, TAS675X_PAGE_CTRL_REG, 0x00); + + /* Exit setup mode */ + regmap_write(regmap, TAS675X_SETUP_REG1, TAS675X_SETUP_EXIT_VAL); + regmap_write(regmap, TAS675X_SETUP_REG2, TAS675X_SETUP_EXIT_VAL); + + /* Write DSP parameters if cached */ + for (i =3D 0; i < ARRAY_SIZE(tas->dsp_params); i++) { + if (tas->dsp_params[i].val) + tas675x_dsp_mem_write(tas, + tas->dsp_params[i].page, + tas->dsp_params[i].reg, + tas->dsp_params[i].val); + } + + /* + * Route fault events to FAULT pin for IRQ handler + * + * ROUTING_1: latched CP fault, CP UVLO, OUTM soft short + * ROUTING_2: non-latching power fault events (+ default OTSD, CBC) + * ROUTING_4: OTW, clip warning, protection shutdown, OC, DC + * ROUTING_5: clock, CBC warning, RTLDG, clip detect + */ + regmap_write(regmap, TAS675X_REPORT_ROUTING_1_REG, 0x70); + regmap_write(regmap, TAS675X_REPORT_ROUTING_2_REG, 0xA3); + regmap_write(regmap, TAS675X_REPORT_ROUTING_4_REG, 0x7E); + regmap_write(regmap, TAS675X_REPORT_ROUTING_5_REG, 0xF3); + + /* Configure GPIO pins if specified in DT */ + if (tas->gpio1_func >=3D 0 || tas->gpio2_func >=3D 0) { + unsigned int gpio_ctrl =3D TAS675X_GPIO_CTRL_RSTVAL; + + tas675x_config_gpio_pin(regmap, tas->gpio1_func, + TAS675X_GPIO1_OUTPUT_SEL_REG, + 0, &gpio_ctrl); + tas675x_config_gpio_pin(regmap, tas->gpio2_func, + TAS675X_GPIO2_OUTPUT_SEL_REG, + 1, &gpio_ctrl); + regmap_write(regmap, TAS675X_GPIO_CTRL_REG, gpio_ctrl); + } + + /* Clear fast boot bits */ + if (tas->fast_boot) + regmap_update_bits(regmap, TAS675X_DC_LDG_CTRL_REG, + TAS675X_LDG_ABORT_BIT | TAS675X_LDG_BYPASS_BIT, + 0); + + /* Clear any stale faults from the boot sequence */ + regmap_read(regmap, TAS675X_POWER_FAULT_LATCHED_REG, &val); + regmap_read(regmap, TAS675X_CLK_FAULT_LATCHED_REG, &val); + regmap_write(regmap, TAS675X_RESET_REG, TAS675X_FAULT_CLEAR); + + return 0; + +err_setup: + regmap_write(regmap, TAS675X_SETUP_REG1, TAS675X_SETUP_EXIT_VAL); + regmap_write(regmap, TAS675X_SETUP_REG2, TAS675X_SETUP_EXIT_VAL); +err: + dev_err(tas->dev, "Init device failed: %d\n", ret); + return ret; +} + +static void tas675x_power_off(struct tas675x_priv *tas) +{ + regcache_cache_only(tas->regmap, true); + regcache_mark_dirty(tas->regmap); + tas675x_hw_disable(tas); +} + +static int tas675x_power_on(struct tas675x_priv *tas) +{ + int ret; + + ret =3D tas675x_hw_enable(tas); + if (ret) + return ret; + + regcache_cache_only(tas->regmap, false); + regcache_mark_dirty(tas->regmap); + + ret =3D tas675x_init_device(tas); + if (ret) + goto err_disable; + + ret =3D regcache_sync(tas->regmap); + if (ret) { + dev_err(tas->dev, "Failed to sync regcache: %d\n", ret); + goto err_disable; + } + + /* Reset fault tracking */ + memset(tas->last_status, 0, sizeof(tas->last_status)); + + return 0; + +err_disable: + tas675x_power_off(tas); + return ret; +} + +static int tas675x_runtime_suspend(struct device *dev) +{ + struct tas675x_priv *tas =3D dev_get_drvdata(dev); + + cancel_delayed_work_sync(&tas->fault_check_work); + tas675x_set_state_all(tas, TAS675X_STATE_SLEEP_BOTH); + + return 0; +} + +static int tas675x_runtime_resume(struct device *dev) +{ + struct tas675x_priv *tas =3D dev_get_drvdata(dev); + + tas675x_set_state_all(tas, TAS675X_STATE_SLEEP_BOTH); + + if (!to_i2c_client(dev)->irq) + schedule_delayed_work(&tas->fault_check_work, + msecs_to_jiffies(TAS675X_FAULT_CHECK_INTERVAL_MS)); + + return 0; +} + +static int tas675x_system_suspend(struct device *dev) +{ + struct tas675x_priv *tas =3D dev_get_drvdata(dev); + int ret; + + ret =3D tas675x_runtime_suspend(dev); + if (ret) + return ret; + + tas675x_power_off(tas); + return 0; +} + +static int tas675x_system_resume(struct device *dev) +{ + struct tas675x_priv *tas =3D dev_get_drvdata(dev); + int ret; + + ret =3D tas675x_power_on(tas); + if (ret) + return ret; + + return tas675x_runtime_resume(dev); +} + +static const struct snd_soc_component_driver soc_codec_dev_tas675x =3D { + .controls =3D tas675x_snd_controls, + .num_controls =3D ARRAY_SIZE(tas675x_snd_controls), + .dapm_widgets =3D tas675x_dapm_widgets, + .num_dapm_widgets =3D ARRAY_SIZE(tas675x_dapm_widgets), + .dapm_routes =3D tas675x_audio_map, + .num_dapm_routes =3D ARRAY_SIZE(tas675x_audio_map), + .endianness =3D 1, +}; + +/* Fault register flags */ +#define TAS675X_FAULT_CRITICAL BIT(0) /* causes FAULT state, FAULT_CLEAR r= equired */ +#define TAS675X_FAULT_TRACK BIT(1) /* track last value, only log on change= */ +#define TAS675X_FAULT_ACTIVE BIT(2) /* skip when no stream is active */ + +struct tas675x_fault_reg { + unsigned int reg; + unsigned int flags; + const char *name; +}; + +static const struct tas675x_fault_reg tas675x_fault_table[] =3D { + /* Critical */ + { TAS675X_OTSD_LATCHED_REG, TAS675X_FAULT_CRITICAL | TAS675X= _FAULT_TRACK, + "Overtemperature Shutdown" }, + { TAS675X_OC_DC_FAULT_LATCHED_REG, TAS675X_FAULT_CRITICAL | TAS675X= _FAULT_TRACK, + "Overcurrent / DC Fault" }, + { TAS675X_RTLDG_OL_SL_FAULT_LATCHED_REG, TAS675X_FAULT_CRITICAL | TAS675X= _FAULT_TRACK, + "Real-Time Load Diagnostic Fault" }, + { TAS675X_CBC_FAULT_WARN_LATCHED_REG, TAS675X_FAULT_CRITICAL | TAS675X= _FAULT_TRACK, + "CBC Fault/Warning" }, + /* Warning */ + { TAS675X_POWER_FAULT_LATCHED_REG, TAS675X_FAULT_TRACK, + "Power Fault" }, + { TAS675X_CLK_FAULT_LATCHED_REG, TAS675X_FAULT_TRACK | TAS675X_FA= ULT_ACTIVE, + "Clock Fault" }, + { TAS675X_OTW_LATCHED_REG, TAS675X_FAULT_TRACK, + "Overtemperature Warning" }, + { TAS675X_CLIP_WARN_LATCHED_REG, TAS675X_FAULT_ACTIVE, + "Clip Warning" }, +}; + +static_assert(ARRAY_SIZE(tas675x_fault_table) =3D=3D TAS675X_FAULT_REGS_NU= M); + +/** + * Read and log all latched fault registers + * Shared by both the polled fault_check_work and IRQ handler paths + * (which are mutually exclusive, only one is active per device). + * + * Returns true if any critical fault was detected that needs FAULT_CLEAR. + */ +static bool tas675x_check_faults(struct tas675x_priv *tas) +{ + struct device *dev =3D tas->dev; + bool is_latched =3D false; + unsigned int reg; + int i, ret; + + for (i =3D 0; i < ARRAY_SIZE(tas675x_fault_table); i++) { + const struct tas675x_fault_reg *f =3D &tas675x_fault_table[i]; + + ret =3D regmap_read(tas->regmap, f->reg, ®); + if (ret) { + if (f->flags & TAS675X_FAULT_CRITICAL) { + dev_err(dev, "failed to read %s: %d\n", f->name, ret); + return is_latched; + } + continue; + } + + if ((f->flags & TAS675X_FAULT_ACTIVE) && + !READ_ONCE(tas->active_playback_dais) && + !READ_ONCE(tas->active_capture_dais)) + continue; + + if ((f->flags & TAS675X_FAULT_CRITICAL) && reg) + is_latched =3D true; + + /* Log on change or on every non-zero read */ + if (reg && (!(f->flags & TAS675X_FAULT_TRACK) || + reg !=3D tas->last_status[i])) { + if (f->flags & TAS675X_FAULT_CRITICAL) + dev_crit(dev, "%s Latched: 0x%02x\n", f->name, reg); + else + dev_warn(dev, "%s Latched: 0x%02x\n", f->name, reg); + } + + if (f->flags & TAS675X_FAULT_TRACK) + tas->last_status[i] =3D reg; + } + + return is_latched; +} + +static void tas675x_fault_check_work(struct work_struct *work) +{ + struct tas675x_priv *tas =3D container_of(work, struct tas675x_priv, + fault_check_work.work); + + if (tas675x_check_faults(tas)) + regmap_write(tas->regmap, TAS675X_RESET_REG, TAS675X_FAULT_CLEAR); + + schedule_delayed_work(&tas->fault_check_work, + msecs_to_jiffies(TAS675X_FAULT_CHECK_INTERVAL_MS)); +} + +static irqreturn_t tas675x_irq_handler(int irq, void *data) +{ + struct tas675x_priv *tas =3D data; + + tas675x_check_faults(tas); + + /* Clear the FAULT pin latch as something latched */ + regmap_write(tas->regmap, TAS675X_RESET_REG, TAS675X_FAULT_CLEAR); + + return IRQ_HANDLED; +} + +static const struct reg_default tas675x_reg_defaults[] =3D { + { TAS675X_PAGE_CTRL_REG, 0x00 }, + { TAS675X_OUTPUT_CTRL_REG, 0x00 }, + { TAS675X_STATE_CTRL_CH1_CH2_REG, TAS675X_STATE_SLEEP_BOTH }, + { TAS675X_STATE_CTRL_CH3_CH4_REG, TAS675X_STATE_SLEEP_BOTH }, + { TAS675X_ISENSE_CTRL_REG, 0x0F }, + { TAS675X_DC_DETECT_CTRL_REG, 0x00 }, + { TAS675X_SCLK_INV_CTRL_REG, 0x00 }, + { TAS675X_AUDIO_IF_CTRL_REG, 0x00 }, + { TAS675X_SDIN_CTRL_REG, 0x0A }, + { TAS675X_SDOUT_CTRL_REG, 0x1A }, + { TAS675X_SDIN_OFFSET_MSB_REG, 0x00 }, + { TAS675X_SDIN_AUDIO_OFFSET_REG, 0x00 }, + { TAS675X_SDIN_LL_OFFSET_REG, 0x60 }, + { TAS675X_SDIN_CH_SWAP_REG, 0x00 }, + { TAS675X_SDOUT_OFFSET_MSB_REG, 0xCF }, + { TAS675X_VPREDICT_OFFSET_REG, 0xFF }, + { TAS675X_ISENSE_OFFSET_REG, 0x00 }, + { TAS675X_SDOUT_EN_REG, 0x00 }, + { TAS675X_LL_EN_REG, 0x00 }, + { TAS675X_RTLDG_EN_REG, 0x10 }, + { TAS675X_DC_BLOCK_BYP_REG, 0x00 }, + { TAS675X_DSP_CTRL_REG, 0x00 }, + { TAS675X_PAGE_AUTO_INC_REG, 0x00 }, + { TAS675X_DIG_VOL_CH1_REG, 0x30 }, + { TAS675X_DIG_VOL_CH2_REG, 0x30 }, + { TAS675X_DIG_VOL_CH3_REG, 0x30 }, + { TAS675X_DIG_VOL_CH4_REG, 0x30 }, + { TAS675X_DIG_VOL_RAMP_CTRL_REG, 0x77 }, + { TAS675X_DIG_VOL_COMBINE_CTRL_REG, 0x00 }, + { TAS675X_AUTO_MUTE_EN_REG, 0x00 }, + { TAS675X_AUTO_MUTE_TIMING_CH1_CH2_REG, 0x00 }, + { TAS675X_AUTO_MUTE_TIMING_CH3_CH4_REG, 0x00 }, + { TAS675X_ANALOG_GAIN_CH1_CH2_REG, 0x00 }, + { TAS675X_ANALOG_GAIN_CH3_CH4_REG, 0x00 }, + { TAS675X_ANALOG_GAIN_RAMP_CTRL_REG, 0x00 }, + { TAS675X_PULSE_INJECTION_EN_REG, 0x03 }, + { TAS675X_CBC_CTRL_REG, 0x07 }, + { TAS675X_CURRENT_LIMIT_CTRL_REG, 0x00 }, + { TAS675X_ISENSE_CAL_REG, 0x00 }, + { TAS675X_PWM_PHASE_CTRL_REG, 0x00 }, + { TAS675X_SS_CTRL_REG, 0x00 }, + { TAS675X_SS_RANGE_CTRL_REG, 0x00 }, + { TAS675X_SS_DWELL_CTRL_REG, 0x00 }, + { TAS675X_RAMP_PHASE_CTRL_GPO_REG, 0x00 }, + { TAS675X_PWM_PHASE_M_CTRL_CH1_REG, 0x00 }, + { TAS675X_PWM_PHASE_M_CTRL_CH2_REG, 0x00 }, + { TAS675X_PWM_PHASE_M_CTRL_CH3_REG, 0x00 }, + { TAS675X_PWM_PHASE_M_CTRL_CH4_REG, 0x00 }, + { TAS675X_DC_LDG_CTRL_REG, 0x00 }, + { TAS675X_DC_LDG_LO_CTRL_REG, 0x00 }, + { TAS675X_DC_LDG_TIME_CTRL_REG, 0x00 }, + { TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG, 0x11 }, + { TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG, 0x11 }, + { TAS675X_AC_LDG_CTRL_REG, 0x10 }, + { TAS675X_TWEETER_DETECT_CTRL_REG, 0x08 }, + { TAS675X_TWEETER_DETECT_THRESH_REG, 0x00 }, + { TAS675X_AC_LDG_FREQ_CTRL_REG, 0xC8 }, + { TAS675X_REPORT_ROUTING_1_REG, 0x00 }, + { TAS675X_OTSD_RECOVERY_EN_REG, 0x00 }, + { TAS675X_REPORT_ROUTING_2_REG, 0xA2 }, + { TAS675X_REPORT_ROUTING_3_REG, 0x00 }, + { TAS675X_REPORT_ROUTING_4_REG, 0x06 }, + { TAS675X_CLIP_DETECT_CTRL_REG, 0x00 }, + { TAS675X_REPORT_ROUTING_5_REG, 0x00 }, + { TAS675X_GPIO1_OUTPUT_SEL_REG, 0x00 }, + { TAS675X_GPIO2_OUTPUT_SEL_REG, 0x00 }, + { TAS675X_GPIO_CTRL_REG, TAS675X_GPIO_CTRL_RSTVAL }, + { TAS675X_OTW_CTRL_CH1_CH2_REG, 0x11 }, + { TAS675X_OTW_CTRL_CH3_CH4_REG, 0x11 }, +}; + +static bool tas675x_is_readable_register(struct device *dev, unsigned int = reg) +{ + switch (reg) { + case TAS675X_RESET_REG: + return false; + default: + return true; + } +} + +static bool tas675x_is_volatile_register(struct device *dev, unsigned int = reg) +{ + switch (reg) { + case TAS675X_RESET_REG: + case TAS675X_BOOK_CTRL_REG: + case TAS675X_AUTO_MUTE_STATUS_REG: + case TAS675X_STATE_REPORT_CH1_CH2_REG: + case TAS675X_STATE_REPORT_CH3_CH4_REG: + case TAS675X_PVDD_SENSE_REG: + case TAS675X_TEMP_GLOBAL_REG: + case TAS675X_TEMP_CH1_CH2_REG: + case TAS675X_TEMP_CH3_CH4_REG: + case TAS675X_FS_MON_REG: + case TAS675X_SCLK_MON_REG: + case TAS675X_POWER_FAULT_STATUS_1_REG: + case TAS675X_POWER_FAULT_STATUS_2_REG: + case TAS675X_OT_FAULT_REG: + case TAS675X_OTW_STATUS_REG: + case TAS675X_CLIP_WARN_STATUS_REG: + case TAS675X_CBC_WARNING_STATUS_REG: + case TAS675X_POWER_FAULT_LATCHED_REG: + case TAS675X_OTSD_LATCHED_REG: + case TAS675X_OTW_LATCHED_REG: + case TAS675X_CLIP_WARN_LATCHED_REG: + case TAS675X_CLK_FAULT_LATCHED_REG: + case TAS675X_RTLDG_OL_SL_FAULT_LATCHED_REG: + case TAS675X_CBC_FAULT_WARN_LATCHED_REG: + case TAS675X_OC_DC_FAULT_LATCHED_REG: + case TAS675X_WARN_OT_MAX_FLAG_REG: + case TAS675X_DC_LDG_REPORT_CH1_CH2_REG ... TAS675X_TWEETER_REPORT_REG: + case TAS675X_CH1_RTLDG_IMP_MSB_REG ... TAS675X_CH4_DC_LDG_DCR_LSB_REG: + return true; + default: + return false; + } +} + +static const struct regmap_range_cfg tas675x_ranges[] =3D { + { + .name =3D "Pages", + .range_min =3D 0, + .range_max =3D TAS675X_PAGE_SIZE * TAS675X_PAGE_SIZE - 1, + .selector_reg =3D TAS675X_PAGE_CTRL_REG, + .selector_mask =3D 0xff, + .selector_shift =3D 0, + .window_start =3D 0, + .window_len =3D TAS675X_PAGE_SIZE, + }, +}; + +static void tas675x_regmap_lock(void *lock_arg) +{ + struct tas675x_priv *tas =3D lock_arg; + + mutex_lock(&tas->io_lock); +} + +static void tas675x_regmap_unlock(void *lock_arg) +{ + struct tas675x_priv *tas =3D lock_arg; + + mutex_unlock(&tas->io_lock); +} + +static const struct regmap_config tas675x_regmap_config =3D { + .reg_bits =3D 8, + .val_bits =3D 8, + .max_register =3D TAS675X_PAGE_SIZE * TAS675X_PAGE_SIZE - 1, + .ranges =3D tas675x_ranges, + .num_ranges =3D ARRAY_SIZE(tas675x_ranges), + .cache_type =3D REGCACHE_MAPLE, + .reg_defaults =3D tas675x_reg_defaults, + .num_reg_defaults =3D ARRAY_SIZE(tas675x_reg_defaults), + .readable_reg =3D tas675x_is_readable_register, + .volatile_reg =3D tas675x_is_volatile_register, +}; + +static int tas675x_i2c_probe(struct i2c_client *client) +{ + struct regmap_config cfg =3D tas675x_regmap_config; + struct tas675x_priv *tas; + u32 val; + int i, ret; + + tas =3D devm_kzalloc(&client->dev, sizeof(*tas), GFP_KERNEL); + if (!tas) + return -ENOMEM; + + tas->dev =3D &client->dev; + i2c_set_clientdata(client, tas); + + mutex_init(&tas->io_lock); + cfg.lock =3D tas675x_regmap_lock; + cfg.unlock =3D tas675x_regmap_unlock; + cfg.lock_arg =3D tas; + tas->regmap =3D devm_regmap_init_i2c(client, &cfg); + if (IS_ERR(tas->regmap)) + return PTR_ERR(tas->regmap); + + memcpy(tas->dsp_params, tas675x_dsp_defaults, sizeof(tas->dsp_params)); + + /* Keep regmap cache-only until hardware is powered on */ + regcache_cache_only(tas->regmap, true); + + tas->dev_type =3D (enum tas675x_type)(unsigned long)device_get_match_data= (tas->dev); + tas->fast_boot =3D device_property_read_bool(tas->dev, "ti,fast-boot"); + + tas->audio_slot =3D -1; + tas->llp_slot =3D -1; + tas->vpredict_slot =3D -1; + tas->isense_slot =3D -1; + if (!device_property_read_u32(tas->dev, "ti,audio-slot-no", &val)) + tas->audio_slot =3D val; + if (!device_property_read_u32(tas->dev, "ti,llp-slot-no", &val)) + tas->llp_slot =3D val; + if (!device_property_read_u32(tas->dev, "ti,vpredict-slot-no", &val)) + tas->vpredict_slot =3D val; + if (!device_property_read_u32(tas->dev, "ti,isense-slot-no", &val)) + tas->isense_slot =3D val; + + tas->gpio1_func =3D tas675x_gpio_func_parse(tas->dev, "ti,gpio1-function"= ); + tas->gpio2_func =3D tas675x_gpio_func_parse(tas->dev, "ti,gpio2-function"= ); + + for (i =3D 0; i < ARRAY_SIZE(tas675x_supply_names); i++) + tas->supplies[i].supply =3D tas675x_supply_names[i]; + + ret =3D devm_regulator_bulk_get(tas->dev, ARRAY_SIZE(tas->supplies), tas-= >supplies); + if (ret) + return dev_err_probe(tas->dev, ret, "Failed to request supplies\n"); + + tas->vbat =3D devm_regulator_get_optional(tas->dev, "vbat"); + if (IS_ERR(tas->vbat) && PTR_ERR(tas->vbat) !=3D -ENODEV) + return dev_err_probe(tas->dev, PTR_ERR(tas->vbat), + "Failed to get vbat supply\n"); + + tas->pd_gpio =3D devm_gpiod_get_optional(tas->dev, "pd", GPIOD_OUT_HIGH); + if (IS_ERR(tas->pd_gpio)) + return dev_err_probe(tas->dev, PTR_ERR(tas->pd_gpio), "Failed pd-gpios\n= "); + + tas->stby_gpio =3D devm_gpiod_get_optional(tas->dev, "stby", GPIOD_OUT_HI= GH); + if (IS_ERR(tas->stby_gpio)) + return dev_err_probe(tas->dev, PTR_ERR(tas->stby_gpio), "Failed stby-gpi= os\n"); + + if (!tas->pd_gpio && !tas->stby_gpio) + return dev_err_probe(tas->dev, -EINVAL, + "At least one of pd-gpios or stby-gpios is required\n"); + + if (client->irq) { + ret =3D devm_request_threaded_irq(tas->dev, client->irq, NULL, + tas675x_irq_handler, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING, + "tas675x-fault", tas); + if (ret) + return dev_err_probe(tas->dev, ret, "Failed to request IRQ\n"); + } + + INIT_DELAYED_WORK(&tas->fault_check_work, tas675x_fault_check_work); + + ret =3D tas675x_power_on(tas); + if (ret) + return ret; + + /* Enable runtime PM with 2s autosuspend */ + pm_runtime_set_autosuspend_delay(tas->dev, 2000); + pm_runtime_use_autosuspend(tas->dev); + pm_runtime_set_active(tas->dev); + pm_runtime_mark_last_busy(tas->dev); + pm_runtime_enable(tas->dev); + + ret =3D devm_snd_soc_register_component(tas->dev, &soc_codec_dev_tas675x, + tas675x_dais, ARRAY_SIZE(tas675x_dais)); + if (ret) + goto err_pm_disable; + + return 0; + +err_pm_disable: + pm_runtime_force_suspend(tas->dev); + pm_runtime_disable(tas->dev); + tas675x_power_off(tas); + return ret; +} + +static void tas675x_i2c_remove(struct i2c_client *client) +{ + struct tas675x_priv *tas =3D dev_get_drvdata(&client->dev); + + pm_runtime_force_suspend(&client->dev); + pm_runtime_disable(&client->dev); + tas675x_power_off(tas); +} + +static const struct dev_pm_ops tas675x_pm_ops =3D { + SYSTEM_SLEEP_PM_OPS(tas675x_system_suspend, tas675x_system_resume) + RUNTIME_PM_OPS(tas675x_runtime_suspend, tas675x_runtime_resume, NULL) +}; + +static const struct of_device_id tas675x_of_match[] =3D { + { .compatible =3D "ti,tas6754", .data =3D (void *)TAS6754 }, + { .compatible =3D "ti,tas67524", .data =3D (void *)TAS6754 }, + { } +}; +MODULE_DEVICE_TABLE(of, tas675x_of_match); + +static const struct i2c_device_id tas675x_i2c_id[] =3D { + { "tas6754", TAS6754 }, + { "tas67524", TAS6754 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tas675x_i2c_id); + +static struct i2c_driver tas675x_i2c_driver =3D { + .driver =3D { + .name =3D "tas675x", + .of_match_table =3D tas675x_of_match, + .pm =3D pm_ptr(&tas675x_pm_ops), + }, + .probe =3D tas675x_i2c_probe, + .remove =3D tas675x_i2c_remove, + .id_table =3D tas675x_i2c_id, +}; + +module_i2c_driver(tas675x_i2c_driver); + +MODULE_AUTHOR("Sen Wang "); +MODULE_DESCRIPTION("ASoC TAS675x Audio Amplifier Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tas675x.h b/sound/soc/codecs/tas675x.h new file mode 100644 index 000000000000..db29bb377336 --- /dev/null +++ b/sound/soc/codecs/tas675x.h @@ -0,0 +1,367 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ALSA SoC Texas Instruments TAS675x Quad-Channel Audio Amplifier + * + * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/ + * Author: Sen Wang + */ + +#ifndef __TAS675X_H__ +#define __TAS675X_H__ + +/* + * Book 0, Page 0 =E2=80=94 Register Addresses + */ + +#define TAS675X_PAGE_SIZE 256 +#define TAS675X_PAGE_REG(page, reg) ((page) * TAS675X_PAGE_SIZE + (reg)) + +/* Page Control & Basic Config */ +#define TAS675X_PAGE_CTRL_REG 0x00 +#define TAS675X_RESET_REG 0x01 +#define TAS675X_OUTPUT_CTRL_REG 0x02 +#define TAS675X_STATE_CTRL_CH1_CH2_REG 0x03 +#define TAS675X_STATE_CTRL_CH3_CH4_REG 0x04 +#define TAS675X_ISENSE_CTRL_REG 0x05 +#define TAS675X_DC_DETECT_CTRL_REG 0x06 + +/* Serial Audio Port */ +#define TAS675X_SCLK_INV_CTRL_REG 0x20 +#define TAS675X_AUDIO_IF_CTRL_REG 0x21 +#define TAS675X_SDIN_CTRL_REG 0x23 +#define TAS675X_SDOUT_CTRL_REG 0x25 +#define TAS675X_SDIN_OFFSET_MSB_REG 0x27 +#define TAS675X_SDIN_AUDIO_OFFSET_REG 0x28 +#define TAS675X_SDIN_LL_OFFSET_REG 0x29 +#define TAS675X_SDIN_CH_SWAP_REG 0x2A +#define TAS675X_SDOUT_OFFSET_MSB_REG 0x2C +#define TAS675X_VPREDICT_OFFSET_REG 0x2D +#define TAS675X_ISENSE_OFFSET_REG 0x2E +#define TAS675X_SDOUT_EN_REG 0x31 +#define TAS675X_LL_EN_REG 0x32 + +/* DSP & Core Audio Control */ +#define TAS675X_RTLDG_EN_REG 0x37 +#define TAS675X_DC_BLOCK_BYP_REG 0x39 +#define TAS675X_DSP_CTRL_REG 0x3A +#define TAS675X_PAGE_AUTO_INC_REG 0x3B + +/* Volume & Mute */ +#define TAS675X_DIG_VOL_CH1_REG 0x40 +#define TAS675X_DIG_VOL_CH2_REG 0x41 +#define TAS675X_DIG_VOL_CH3_REG 0x42 +#define TAS675X_DIG_VOL_CH4_REG 0x43 +#define TAS675X_DIG_VOL_RAMP_CTRL_REG 0x44 +#define TAS675X_DIG_VOL_COMBINE_CTRL_REG 0x46 +#define TAS675X_AUTO_MUTE_EN_REG 0x47 +#define TAS675X_AUTO_MUTE_TIMING_CH1_CH2_REG 0x48 +#define TAS675X_AUTO_MUTE_TIMING_CH3_CH4_REG 0x49 + +/* Analog Gain & Power Stage */ +#define TAS675X_ANALOG_GAIN_CH1_CH2_REG 0x4A +#define TAS675X_ANALOG_GAIN_CH3_CH4_REG 0x4B +#define TAS675X_ANALOG_GAIN_RAMP_CTRL_REG 0x4E +#define TAS675X_PULSE_INJECTION_EN_REG 0x52 +#define TAS675X_CBC_CTRL_REG 0x54 +#define TAS675X_CURRENT_LIMIT_CTRL_REG 0x55 +#define TAS675X_DAC_CLK_REG 0x5A +#define TAS675X_ISENSE_CAL_REG 0x5B + +/* Spread Spectrum & PWM Phase */ +#define TAS675X_PWM_PHASE_CTRL_REG 0x60 +#define TAS675X_SS_CTRL_REG 0x61 +#define TAS675X_SS_RANGE_CTRL_REG 0x62 +#define TAS675X_SS_DWELL_CTRL_REG 0x66 +#define TAS675X_RAMP_PHASE_CTRL_GPO_REG 0x68 +#define TAS675X_PWM_PHASE_M_CTRL_CH1_REG 0x69 +#define TAS675X_PWM_PHASE_M_CTRL_CH2_REG 0x6A +#define TAS675X_PWM_PHASE_M_CTRL_CH3_REG 0x6B +#define TAS675X_PWM_PHASE_M_CTRL_CH4_REG 0x6C + +/* Status & Reporting */ +#define TAS675X_AUTO_MUTE_STATUS_REG 0x71 +#define TAS675X_STATE_REPORT_CH1_CH2_REG 0x72 +#define TAS675X_STATE_REPORT_CH3_CH4_REG 0x73 +#define TAS675X_PVDD_SENSE_REG 0x74 +#define TAS675X_TEMP_GLOBAL_REG 0x75 +#define TAS675X_FS_MON_REG 0x76 +#define TAS675X_SCLK_MON_REG 0x77 +#define TAS675X_REPORT_ROUTING_1_REG 0x7C + +/* Memory Paging & Book Control */ +#define TAS675X_SETUP_REG1 0x7D +#define TAS675X_SETUP_REG2 0x7E +#define TAS675X_BOOK_CTRL_REG 0x7F + +/* Fault Status */ +#define TAS675X_POWER_FAULT_STATUS_1_REG 0x7D +#define TAS675X_POWER_FAULT_STATUS_2_REG 0x80 +#define TAS675X_OT_FAULT_REG 0x81 +#define TAS675X_OTW_STATUS_REG 0x82 +#define TAS675X_CLIP_WARN_STATUS_REG 0x83 +#define TAS675X_CBC_WARNING_STATUS_REG 0x85 + +/* Latched Fault Registers */ +#define TAS675X_POWER_FAULT_LATCHED_REG 0x86 +#define TAS675X_OTSD_LATCHED_REG 0x87 +#define TAS675X_OTW_LATCHED_REG 0x88 +#define TAS675X_CLIP_WARN_LATCHED_REG 0x89 +#define TAS675X_CLK_FAULT_LATCHED_REG 0x8A +#define TAS675X_RTLDG_OL_SL_FAULT_LATCHED_REG 0x8B +#define TAS675X_CBC_FAULT_WARN_LATCHED_REG 0x8D +#define TAS675X_OC_DC_FAULT_LATCHED_REG 0x8E +#define TAS675X_OTSD_RECOVERY_EN_REG 0x8F + +/* Protection & Routing Controls */ +#define TAS675X_REPORT_ROUTING_2_REG 0x90 +#define TAS675X_REPORT_ROUTING_3_REG 0x91 +#define TAS675X_REPORT_ROUTING_4_REG 0x92 +#define TAS675X_CLIP_DETECT_CTRL_REG 0x93 +#define TAS675X_REPORT_ROUTING_5_REG 0x94 + +/* GPIO Pin Configuration */ +#define TAS675X_GPIO1_OUTPUT_SEL_REG 0x95 +#define TAS675X_GPIO2_OUTPUT_SEL_REG 0x96 +#define TAS675X_GPIO_INPUT_SLEEP_HIZ_REG 0x9B +#define TAS675X_GPIO_INPUT_PLAY_SLEEP_REG 0x9C +#define TAS675X_GPIO_INPUT_MUTE_REG 0x9D +#define TAS675X_GPIO_INPUT_SYNC_REG 0x9E +#define TAS675X_GPIO_INPUT_SDIN2_REG 0x9F +#define TAS675X_GPIO_CTRL_REG 0xA0 +#define TAS675X_GPIO_INVERT_REG 0xA1 + +/* Load Diagnostics Config */ +#define TAS675X_DC_LDG_CTRL_REG 0xB0 +#define TAS675X_DC_LDG_LO_CTRL_REG 0xB1 +#define TAS675X_DC_LDG_TIME_CTRL_REG 0xB2 +#define TAS675X_DC_LDG_SL_CH1_CH2_CTRL_REG 0xB3 +#define TAS675X_DC_LDG_SL_CH3_CH4_CTRL_REG 0xB4 +#define TAS675X_AC_LDG_CTRL_REG 0xB5 +#define TAS675X_TWEETER_DETECT_CTRL_REG 0xB6 +#define TAS675X_TWEETER_DETECT_THRESH_REG 0xB7 +#define TAS675X_AC_LDG_FREQ_CTRL_REG 0xB8 +#define TAS675X_TEMP_CH1_CH2_REG 0xBB +#define TAS675X_TEMP_CH3_CH4_REG 0xBC +#define TAS675X_WARN_OT_MAX_FLAG_REG 0xBD + +/* DC Load Diagnostic Reports */ +#define TAS675X_DC_LDG_REPORT_CH1_CH2_REG 0xC0 +#define TAS675X_DC_LDG_REPORT_CH3_CH4_REG 0xC1 +#define TAS675X_DC_LDG_RESULT_REG 0xC2 +#define TAS675X_AC_LDG_REPORT_CH1_R_REG 0xC3 +#define TAS675X_AC_LDG_REPORT_CH1_I_REG 0xC4 +#define TAS675X_AC_LDG_REPORT_CH2_R_REG 0xC5 +#define TAS675X_AC_LDG_REPORT_CH2_I_REG 0xC6 +#define TAS675X_AC_LDG_REPORT_CH3_R_REG 0xC7 +#define TAS675X_AC_LDG_REPORT_CH3_I_REG 0xC8 +#define TAS675X_AC_LDG_REPORT_CH4_R_REG 0xC9 +#define TAS675X_AC_LDG_REPORT_CH4_I_REG 0xCA +#define TAS675X_TWEETER_REPORT_REG 0xCB + +/* RTLDG Impedance */ +#define TAS675X_CH1_RTLDG_IMP_MSB_REG 0xD1 +#define TAS675X_CH1_RTLDG_IMP_LSB_REG 0xD2 +#define TAS675X_CH2_RTLDG_IMP_MSB_REG 0xD3 +#define TAS675X_CH2_RTLDG_IMP_LSB_REG 0xD4 +#define TAS675X_CH3_RTLDG_IMP_MSB_REG 0xD5 +#define TAS675X_CH3_RTLDG_IMP_LSB_REG 0xD6 +#define TAS675X_CH4_RTLDG_IMP_MSB_REG 0xD7 +#define TAS675X_CH4_RTLDG_IMP_LSB_REG 0xD8 + +/* DC Load Diagnostic Resistance */ +#define TAS675X_DC_LDG_DCR_MSB_REG 0xD9 +#define TAS675X_CH1_DC_LDG_DCR_LSB_REG 0xDA +#define TAS675X_CH2_DC_LDG_DCR_LSB_REG 0xDB +#define TAS675X_CH3_DC_LDG_DCR_LSB_REG 0xDC +#define TAS675X_CH4_DC_LDG_DCR_LSB_REG 0xDD + +/* Over-Temperature Warning */ +#define TAS675X_OTW_CTRL_CH1_CH2_REG 0xE2 +#define TAS675X_OTW_CTRL_CH3_CH4_REG 0xE3 + +/* RESET_REG (all bits auto-clear) */ +#define TAS675X_DEVICE_RESET BIT(4) +#define TAS675X_FAULT_CLEAR BIT(3) +#define TAS675X_REGISTER_RESET BIT(0) + +/* STATE_CTRL and STATE_REPORT =E2=80=94 Channel state values */ +#define TAS675X_STATE_DEEPSLEEP 0x00 +#define TAS675X_STATE_LOAD_DIAG 0x01 +#define TAS675X_STATE_SLEEP 0x02 +#define TAS675X_STATE_HIZ 0x03 +#define TAS675X_STATE_PLAY 0x04 + +/* Additional STATE_REPORT values */ +#define TAS675X_STATE_FAULT 0x05 +#define TAS675X_STATE_AUTOREC 0x06 + +/* Combined values for both channel pairs in one register */ +#define TAS675X_STATE_DEEPSLEEP_BOTH \ + (TAS675X_STATE_DEEPSLEEP | (TAS675X_STATE_DEEPSLEEP << 4)) +#define TAS675X_STATE_LOAD_DIAG_BOTH \ + (TAS675X_STATE_LOAD_DIAG | (TAS675X_STATE_LOAD_DIAG << 4)) +#define TAS675X_STATE_SLEEP_BOTH \ + (TAS675X_STATE_SLEEP | (TAS675X_STATE_SLEEP << 4)) +#define TAS675X_STATE_HIZ_BOTH \ + (TAS675X_STATE_HIZ | (TAS675X_STATE_HIZ << 4)) +#define TAS675X_STATE_PLAY_BOTH \ + (TAS675X_STATE_PLAY | (TAS675X_STATE_PLAY << 4)) +#define TAS675X_STATE_FAULT_BOTH \ + (TAS675X_STATE_FAULT | (TAS675X_STATE_FAULT << 4)) + +/* STATE_CTRL_CH1_CH2 / STATE_CTRL_CH3_CH4 =E2=80=94 mute bits */ +#define TAS675X_CH1_MUTE_BIT BIT(7) +#define TAS675X_CH2_MUTE_BIT BIT(3) +#define TAS675X_CH_MUTE_BOTH (TAS675X_CH1_MUTE_BIT | TAS67= 5X_CH2_MUTE_BIT) + +/* SCLK_INV_CTRL_REG */ +#define TAS675X_SCLK_INV_TX_BIT BIT(5) +#define TAS675X_SCLK_INV_RX_BIT BIT(4) +#define TAS675X_SCLK_INV_MASK (TAS675X_SCLK_INV_TX_BIT | TAS= 675X_SCLK_INV_RX_BIT) + +/* AUDIO_IF_CTRL_REG */ +#define TAS675X_TDM_EN_BIT BIT(4) +#define TAS675X_SAP_FMT_MASK GENMASK(3, 2) +#define TAS675X_SAP_FMT_I2S (0x00 << 2) +#define TAS675X_SAP_FMT_TDM (0x01 << 2) +#define TAS675X_SAP_FMT_RIGHT_J (0x02 << 2) +#define TAS675X_SAP_FMT_LEFT_J (0x03 << 2) +#define TAS675X_FS_PULSE_MASK GENMASK(1, 0) +#define TAS675X_FS_PULSE_SHORT 0x01 + +/* SDIN_CTRL_REG */ +#define TAS675X_SDIN_AUDIO_WL_MASK GENMASK(3, 2) +#define TAS675X_SDIN_LL_WL_MASK GENMASK(1, 0) +#define TAS675X_SDIN_WL_MASK (TAS675X_SDIN_AUDIO_WL_MASK |= TAS675X_SDIN_LL_WL_MASK) + +/* SDOUT_CTRL_REG */ +#define TAS675X_SDOUT_SELECT_MASK GENMASK(7, 4) +#define TAS675X_SDOUT_SELECT_TDM_SDOUT1 0x00 +#define TAS675X_SDOUT_SELECT_NON_TDM 0x10 +#define TAS675X_SDOUT_VP_WL_MASK GENMASK(3, 2) +#define TAS675X_SDOUT_IS_WL_MASK GENMASK(1, 0) +#define TAS675X_SDOUT_WL_MASK (TAS675X_SDOUT_VP_WL_MASK | T= AS675X_SDOUT_IS_WL_MASK) + +/* SDOUT_EN_REG */ +#define TAS675X_SDOUT_NON_TDM_SEL_MASK GENMASK(5, 4) +#define TAS675X_SDOUT_NON_TDM_SEL_VPREDICT (0x0 << 4) +#define TAS675X_SDOUT_NON_TDM_SEL_ISENSE (0x1 << 4) +#define TAS675X_SDOUT_EN_VPREDICT BIT(0) +#define TAS675X_SDOUT_EN_ISENSE BIT(1) +#define TAS675X_SDOUT_EN_NON_TDM_ALL GENMASK(1, 0) + +/* Word length values (shared by SDIN_CTRL and SDOUT_CTRL) */ +#define TAS675X_WL_16BIT 0x00 +#define TAS675X_WL_20BIT 0x01 +#define TAS675X_WL_24BIT 0x02 +#define TAS675X_WL_32BIT 0x03 + +/* SDIN_OFFSET_MSB_REG */ +#define TAS675X_SDIN_AUDIO_OFF_MSB_MASK GENMASK(7, 6) +#define TAS675X_SDIN_LL_OFF_MSB_MASK GENMASK(5, 4) + +/* SDOUT_OFFSET_MSB_REG */ +#define TAS675X_SDOUT_VP_OFF_MSB_MASK GENMASK(7, 6) +#define TAS675X_SDOUT_IS_OFF_MSB_MASK GENMASK(5, 4) + +/* RTLDG_EN_REG */ +#define TAS675X_RTLDG_CLIP_MASK_BIT BIT(4) +#define TAS675X_RTLDG_CH_EN_MASK GENMASK(3, 0) + +/* DC_LDG_CTRL_REG */ +#define TAS675X_LDG_ABORT_BIT BIT(7) +#define TAS675X_LDG_BUFFER_WAIT_MASK GENMASK(6, 5) +#define TAS675X_LDG_WAIT_BYPASS_BIT BIT(2) +#define TAS675X_SLOL_DISABLE_BIT BIT(1) +#define TAS675X_LDG_BYPASS_BIT BIT(0) + +/* DC_LDG_TIME_CTRL_REG */ +#define TAS675X_LDG_RAMP_SLOL_MASK GENMASK(7, 6) +#define TAS675X_LDG_SETTLING_SLOL_MASK GENMASK(5, 4) +#define TAS675X_LDG_RAMP_S2PG_MASK GENMASK(3, 2) +#define TAS675X_LDG_SETTLING_S2PG_MASK GENMASK(1, 0) + +/* AC_LDG_CTRL_REG */ +#define TAS675X_AC_DIAG_GAIN_BIT BIT(4) +#define TAS675X_AC_DIAG_START_MASK GENMASK(3, 0) + +/* DC_LDG_RESULT_REG */ +#define TAS675X_DC_LDG_LO_RESULT_MASK GENMASK(7, 4) +#define TAS675X_DC_LDG_PASS_MASK GENMASK(3, 0) + +/* Load Diagnostics Timing Constants */ +#define TAS675X_POLL_INTERVAL_US 10000 +#define TAS675X_STATE_TRANSITION_TIMEOUT_US 50000 +#define TAS675X_DC_LDG_TIMEOUT_US 300000 +#define TAS675X_AC_LDG_TIMEOUT_US 400000 + +/* GPIO_CTRL_REG */ +#define TAS675X_GPIO1_OUTPUT_EN BIT(7) +#define TAS675X_GPIO2_OUTPUT_EN BIT(6) +#define TAS675X_GPIO_CTRL_RSTVAL 0x22 + +/* GPIO output select values */ +#define TAS675X_GPIO_SEL_LOW 0x00 +#define TAS675X_GPIO_SEL_AUTO_MUTE_ALL 0x02 +#define TAS675X_GPIO_SEL_AUTO_MUTE_CH4 0x03 +#define TAS675X_GPIO_SEL_AUTO_MUTE_CH3 0x04 +#define TAS675X_GPIO_SEL_AUTO_MUTE_CH2 0x05 +#define TAS675X_GPIO_SEL_AUTO_MUTE_CH1 0x06 +#define TAS675X_GPIO_SEL_SDOUT2 0x08 +#define TAS675X_GPIO_SEL_SDOUT1 0x09 +#define TAS675X_GPIO_SEL_WARN 0x0A +#define TAS675X_GPIO_SEL_FAULT 0x0B +#define TAS675X_GPIO_SEL_CLOCK_SYNC 0x0E +#define TAS675X_GPIO_SEL_INVALID_CLK 0x0F +#define TAS675X_GPIO_SEL_HIGH 0x13 + +/* GPIO input function encoding (flag bit | function ID) */ +#define TAS675X_GPIO_FUNC_INPUT 0x100 + +/* Input Function IDs */ +#define TAS675X_GPIO_IN_ID_MUTE 0 +#define TAS675X_GPIO_IN_ID_PHASE_SYNC 1 +#define TAS675X_GPIO_IN_ID_SDIN2 2 +#define TAS675X_GPIO_IN_ID_DEEP_SLEEP 3 +#define TAS675X_GPIO_IN_ID_HIZ 4 +#define TAS675X_GPIO_IN_ID_PLAY 5 +#define TAS675X_GPIO_IN_ID_SLEEP 6 +#define TAS675X_GPIO_IN_NUM 7 + +#define TAS675X_GPIO_IN_MUTE (TAS675X_GPIO_FUNC_INPUT | TA= S675X_GPIO_IN_ID_MUTE) +#define TAS675X_GPIO_IN_PHASE_SYNC \ + (TAS675X_GPIO_FUNC_INPUT | TAS675X_GPIO_IN_ID_PHASE_SYNC) +#define TAS675X_GPIO_IN_SDIN2 (TAS675X_GPIO_FUNC_INPUT | TA= S675X_GPIO_IN_ID_SDIN2) +#define TAS675X_GPIO_IN_DEEP_SLEEP \ + (TAS675X_GPIO_FUNC_INPUT | TAS675X_GPIO_IN_ID_DEEP_SLEEP) +#define TAS675X_GPIO_IN_HIZ (TAS675X_GPIO_FUNC_INPUT | TA= S675X_GPIO_IN_ID_HIZ) +#define TAS675X_GPIO_IN_PLAY (TAS675X_GPIO_FUNC_INPUT | TA= S675X_GPIO_IN_ID_PLAY) +#define TAS675X_GPIO_IN_SLEEP (TAS675X_GPIO_FUNC_INPUT | TA= S675X_GPIO_IN_ID_SLEEP) + +/* GPIO input 3-bit mux field masks */ +#define TAS675X_GPIO_IN_MUTE_MASK GENMASK(2, 0) +#define TAS675X_GPIO_IN_SYNC_MASK GENMASK(2, 0) +#define TAS675X_GPIO_IN_SDIN2_MASK GENMASK(6, 4) +#define TAS675X_GPIO_IN_DEEP_SLEEP_MASK GENMASK(6, 4) +#define TAS675X_GPIO_IN_HIZ_MASK GENMASK(2, 0) +#define TAS675X_GPIO_IN_PLAY_MASK GENMASK(6, 4) +#define TAS675X_GPIO_IN_SLEEP_MASK GENMASK(2, 0) + +/* Book addresses for tas675x_select_book() */ +#define TAS675X_BOOK_DEFAULT 0x00 +#define TAS675X_BOOK_DSP 0x8C + +/* DSP memory addresses (DSP Book) */ +#define TAS675X_DSP_PAGE_RTLDG 0x22 +#define TAS675X_DSP_RTLDG_OL_THRESH_REG 0x98 +#define TAS675X_DSP_RTLDG_SL_THRESH_REG 0x9C + +#define TAS675X_DSP_PARAM_ID_OL_THRESH 0 +#define TAS675X_DSP_PARAM_ID_SL_THRESH 1 + +/* Setup Mode Entry/Exit*/ +#define TAS675X_SETUP_ENTER_VAL1 0x11 +#define TAS675X_SETUP_ENTER_VAL2 0xFF +#define TAS675X_SETUP_EXIT_VAL 0x00 + +#endif /* __TAS675X_H__ */ --=20 2.43.0 From nobody Wed Apr 1 08:37:52 2026 Received: from DM5PR21CU001.outbound.protection.outlook.com (mail-centralusazon11011014.outbound.protection.outlook.com [52.101.62.14]) (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 9EC5A35E95A; Wed, 1 Apr 2026 02:42:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.62.14 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011367; cv=fail; b=uq02JdBmL/HQyfDFE1FVICNg6BhhvrRmhgOvSdHkKaRd5tmgRQScLZlUhkKk8Z+tWWhkZTOy/0BFsf4nfG0c6ghN3JeNI89XXMUbtunPElxiGM9WD4Fhs3nrqqdlCYt4tC9tmzro+N8l9oKvWjP7BnhryVRo0sgjrjFshtLMyJg= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011367; c=relaxed/simple; bh=qajO+3fmBPsI+4dL9jkT7S1JH8eh1SPm6U/AN2/g2XU=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=otu+IWVRuLMNr7ddiHkGACLl996nqdp9d2x423ywQLw0z6nM53jM7nACNc3wPPQWKjAkm8dGCIzVvPkOzrWXKPUjspVjXhmom3AA2nrQe7xU8tGIcbffGVp8kCaMu+JvjPxW5GmbWiYHoMLFR2bNyWano0Q/aqQUcjatsVMF198= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=Uh1gUTPX; arc=fail smtp.client-ip=52.101.62.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="Uh1gUTPX" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=u/wAfBuzyyNwEAq7IRFOTB4tuag5y9/tQpPEMRFv2qOvwmkpRnURDI64zG8UMTHb7CtkRM/SbL+5TMsikwmhUMKPB5Ipww7Zk3CRgS+tRoqZovT3B3xnHn+sM1oT/oZPAOti8HSEiTuA+SpoDEdMgLdBu1vmrMDgstcOYvlp6mvTTIeDJD/l1J9/usgE8iR7ifT4T2o2MqhnkDeFiyntp1C1o7y5H7/aSPv8r1aEJuL74EKNvBbYMpFVYpH/aXdpaJ/7JA4/YtWQ6PMt6wIGLtg8Vx62+jru5OBmA+grTouWmE7vaLo6bo9pdgXhZxT6MK8D7SBQxNMSVnefiBwuAw== 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=wkSxadPlX+ceW9TliS7LuElDmMTuTndw07ZjRSoItF4=; b=osU+97KanacO67vKF6DxdtQcfhLQc+z4qkpFroDiKa/xIQWmwfa1zFxPxBytlkp75aI3s9AumSJzOr1pZF37fItZEDCnZab1AgFmvL/2EcM8Ml9ISKO8h7Ih0LKW6oZPtYe0qb/B1LT3qh4YnhuVRuQ9zxPpkFc2Jb4J4Mk/C9nfdPwu0Q/gcKgxJDj974IqmUSEWZk/zQVGVw4WDzJHJq2pPEgEC3pFFMUl7RLmyg9iSCaasUvwaDr/xBQxmNG9CDBKhvMKNwXT33ystCqbUbzIvvX9tVGSDcVMkz3bQ5BEeD+xwkj/SIISNWQ41BPWc1G+j3xvABt1IL3okxMPDQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.21.194) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=ti.com; dmarc=pass (p=quarantine sp=none pct=100) action=none header.from=ti.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=wkSxadPlX+ceW9TliS7LuElDmMTuTndw07ZjRSoItF4=; b=Uh1gUTPXKkEeb+605d2jLXbMyh3AIn9XATfwnhHlD4RCyOSTdaTvoNz3ie002FJIhudHkSsHhirvC+W80b8vK5kPyAvNaBx2mQkFrqNzGuRXDVdTPEWB+dOS2uscUlZU8Uq+3KBZJGV2b6ZakAs647AhPCwZZfZeGLkGcdooYnc= Received: from BN9PR03CA0241.namprd03.prod.outlook.com (2603:10b6:408:ff::6) by SJ0PR10MB4687.namprd10.prod.outlook.com (2603:10b6:a03:2d8::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.15; Wed, 1 Apr 2026 02:42:25 +0000 Received: from BN2PEPF000044A1.namprd02.prod.outlook.com (2603:10b6:408:ff:cafe::9a) by BN9PR03CA0241.outlook.office365.com (2603:10b6:408:ff::6) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9745.28 via Frontend Transport; Wed, 1 Apr 2026 02:42:25 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.21.194) smtp.mailfrom=ti.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=ti.com; Received-SPF: Pass (protection.outlook.com: domain of ti.com designates 198.47.21.194 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.21.194; helo=flwvzet200.ext.ti.com; pr=C Received: from flwvzet200.ext.ti.com (198.47.21.194) by BN2PEPF000044A1.mail.protection.outlook.com (10.167.243.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.17 via Frontend Transport; Wed, 1 Apr 2026 02:42:24 +0000 Received: from DFLE204.ent.ti.com (10.64.6.62) by flwvzet200.ext.ti.com (10.248.192.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:16 -0500 Received: from DFLE205.ent.ti.com (10.64.6.63) by DFLE204.ent.ti.com (10.64.6.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:16 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) by DFLE205.ent.ti.com (10.64.6.63) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Tue, 31 Mar 2026 21:42:16 -0500 Received: from localhost (mz02jj9v.dhcp.ti.com [128.247.81.246]) by lelvem-mr05.itg.ti.com (8.18.1/8.18.1) with ESMTP id 6312gGhZ3899127; Tue, 31 Mar 2026 21:42:16 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH 3/4] Documentation: sound: Add TAS675x codec mixer controls documentation Date: Tue, 31 Mar 2026 21:42:08 -0500 Message-ID: <20260401024210.28542-4-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401024210.28542-1-sen@ti.com> References: <20260401024210.28542-1-sen@ti.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN2PEPF000044A1:EE_|SJ0PR10MB4687:EE_ X-MS-Office365-Filtering-Correlation-Id: e4569cad-0424-4627-0f58-08de8f984e5f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700016|376014|7416014|82310400026|1800799024|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: RIbhvj0udIsF1DN/r3V7r29NIxyF4L3ZgnAMtjc0gMs9/rWUs29X1ma0gYMBmwGj69GbwDr4lG5CdhSE9Hi9v6BVQItag4sD8Fwi4+yh8KAlRO9Zlz0ErTm6k57X9/IGM/U2FqismeeyAo0utNyw6RplqJtonkn+69i89osobqZpk3iq63h9eEDd1hStGOMOZMcixEBzm0DqZsi1KtrSsfYoLy6fDn+6ENeAT0Q0Ct2N1Lq/wEsf/WnYlInaghtVjDsYAsOSIaVrU6tQxVq3Gj5JS4TeS9ybZmV0Gx+ff//d3ZgV5Rifha6lmSa2DKbWwSDQB5M/T60MYUcfEgOQeW0ltsslRf3AzxOCUKz+UcAZjn+fgvJlcij5+4zCHg3NuwNqYDtwrUOWGrv+l7Hh1xDzrL7kQBrTEVEcY1W3hppitDBETOhEXE9lnxPEN8p1tcHPFunBh3si75/NwqqpQ6H9b4Ll6w+5MWRrLW/+k4mFW1W98ogKC85+cUGodGx/EdpwJH/L3ZYnFydX3shRjyD25/Ls75OJ0g8ZDvhWbWW7UTaYCeFBXR3Qfgq4/4DpZTuF6HxNJxBqqdrdi1JEtrwYpsVxVmVRsCPBfxrxFEdhHoUCfxaFNaBejRDMWnCS3SQ/8mALQs+RyQ2685O1abbUZacwzsUvnTy0RMdP08BLchvBImpaL0XJAnBA4ezNPSmkGzj0cazT0b9GgpNeNiRDwILJHhtIH7kYAv/P8RkLqTPrGMYu4i8varsKPb3bEZkeNrQZM9e+3WpFWFvncA== X-Forefront-Antispam-Report: CIP:198.47.21.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:flwvzet200.ext.ti.com;PTR:ErrorRetry;CAT:NONE;SFS:(13230040)(36860700016)(376014)(7416014)(82310400026)(1800799024)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: XPXRyfzkJySNg2wxQ8eKubUSX8O3gNEwvD0VjcUQCePXmpRP7XbTWt2ukgiavtqTLQ5Sbqz/J9V67GkSHpRqa9AX/kgByzjWuirBGOzIaczREWoadUtAuFTfQ3hU/vhU/yhbilpQPxsB5QAHaq0sE/TvsznBioOPMbR+S4DbXodI7obi7h8Av3iwKCZ9X3tYnqnX6jEA9v77bdgnf61XHe/gYf2LgQIx5xXytF+2eUkQjkE7D5kRcRZh4OQ970Ej6r+watvyUszL0dQLNM7JaSGLifGk0JZ2/eXDWm8mCZKor7qdjzDYfWB1CqyJLck8zHi+Xi0+D8+tzYz1+E9P3ehjafK1DvVtYa7hEJdDObVnRg/oRXK0zThOoD+c+hi3AHNB5AxnRC70bdvFFhIWxNVjdHQ2LEqQYN5e7CKOClG/4zvi1xvpCT5Nf7g9ekHe X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 02:42:24.4646 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: e4569cad-0424-4627-0f58-08de8f984e5f X-MS-Exchange-CrossTenant-Id: e5b49634-450b-4709-8abb-1e2b19b982b7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=e5b49634-450b-4709-8abb-1e2b19b982b7;Ip=[198.47.21.194];Helo=[flwvzet200.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: BN2PEPF000044A1.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ0PR10MB4687 Add ALSA mixer controls documentation for the TAS675x driver, covering DSP signal path modes, volume controls, load diagnostics, and fault monitoring. Signed-off-by: Sen Wang --- Documentation/sound/codecs/index.rst | 1 + Documentation/sound/codecs/tas675x.rst | 618 +++++++++++++++++++++++++ 2 files changed, 619 insertions(+) create mode 100644 Documentation/sound/codecs/tas675x.rst diff --git a/Documentation/sound/codecs/index.rst b/Documentation/sound/cod= ecs/index.rst index 2cb95d87bbef..7594d0a38d6b 100644 --- a/Documentation/sound/codecs/index.rst +++ b/Documentation/sound/codecs/index.rst @@ -7,3 +7,4 @@ Codec-Specific Information :maxdepth: 2 =20 cs35l56 + tas675x diff --git a/Documentation/sound/codecs/tas675x.rst b/Documentation/sound/c= odecs/tas675x.rst new file mode 100644 index 000000000000..334b1d8be3ea --- /dev/null +++ b/Documentation/sound/codecs/tas675x.rst @@ -0,0 +1,618 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +TAS675x Codec Mixer Controls +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +This document describes the ALSA mixer controls for the TAS675x +4-channel automotive Class-D amplifier driver. + +For device tree bindings, see: +Documentation/devicetree/bindings/sound/ti,tas675x.yaml + +DSP Signal Path Mode +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +DSP Signal Path Mode +-------------------- + +:Description: Signal processing mode selection. +:Type: Enumerated +:Default: Normal +:Options: Normal, LLP, FFLP + +Normal + Full DSP with all features available. + +LLP (Low Latency Path) + Bypasses DSP processing. DSP protection features (Thermal Foldback, + PVDD Foldback, Clip Detect) and Real-Time Load Diagnostics unavailable. + +FFLP (Full Feature Low Latency Path) + Reduced latency. Real-Time Load Diagnostics unavailable. + +The following controls are unavailable in LLP mode: +``Thermal Foldback Switch``, ``PVDD Foldback Switch``, +``DC Blocker Bypass Switch``, ``Clip Detect Switch``, ``Audio SDOUT Switch= ``. + +The following controls require Normal mode (unavailable in FFLP and LLP): +``CHx RTLDG Switch``, ``RTLDG Clip Mask Switch``, ``ISENSE Calibration Swi= tch``, +``RTLDG Open Load Threshold``, ``RTLDG Short Load Threshold``, +``CHx RTLDG Impedance``, ``RTLDG Fault Latched``. + +Volume Controls +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Analog Playback Volume +---------------------- + +:Description: Analog output gain for all channels (CH1/CH2 and CH3/CH4 pai= rs). +:Type: Volume (TLV) +:Default: 0 dB +:Range: -15.5 dB to 0 dB (0.5 dB steps) + +Analog Gain Ramp Step +--------------------- + +:Description: Anti-pop ramp step duration for analog gain transitions. +:Type: Enumerated +:Default: 15us +:Options: 15us, 60us, 200us, 400us + +CHx Digital Playback Volume +--------------------------- + +:Description: Per-channel digital volume control (x =3D 1, 2, 3, 4). +:Type: Volume (TLV) +:Default: 0 dB +:Range: -103 dB to 0 dB (0.5 dB steps) +:Bounds: 0x30 (min/mute) to 0xFF (max) + +Volume Ramp Down Rate +--------------------- + +:Description: Update frequency during mute transition. +:Type: Enumerated +:Default: 16 FS +:Options: 4 FS, 16 FS, 32 FS, Instant + +Volume Ramp Down Step +--------------------- + +:Description: dB change per update during mute. +:Type: Enumerated +:Default: 0.5dB +:Options: 4dB, 2dB, 1dB, 0.5dB + +Volume Ramp Up Rate +------------------- + +:Description: Update frequency during unmute transition. +:Type: Enumerated +:Default: 16 FS +:Options: 4 FS, 16 FS, 32 FS, Instant + +Volume Ramp Up Step +------------------- + +:Description: dB change per update during unmute. +:Type: Enumerated +:Default: 0.5dB +:Options: 4dB, 2dB, 1dB, 0.5dB + +CH1/2 Volume Combine +-------------------- + +:Description: Links digital volume controls for CH1 and CH2. +:Type: Enumerated +:Default: Independent +:Options: Independent, CH2 follows CH1, CH1 follows CH2 + +CH3/4 Volume Combine +-------------------- + +:Description: Links digital volume controls for CH3 and CH4. +:Type: Enumerated +:Default: Independent +:Options: Independent, CH4 follows CH3, CH3 follows CH4 + +Auto Mute & Silence Detection +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D + +CHx Auto Mute Switch +-------------------- + +:Description: Enables automatic muting on zero-signal detection (x =3D 1, = 2, 3, 4). +:Type: Boolean Switch +:Default: Disabled (0) + +Auto Mute Combine Switch +------------------------ + +:Description: Coordinated muting behaviour across all channels. +:Type: Boolean Switch +:Default: Disabled (0) +:Behavior: Disabled: channels mute independently when their signal is z= ero. + Enabled: all channels mute together only when all detect zero + signal; unmute when any channel has non-zero signal. + +CHx Auto Mute Time +------------------ + +:Description: Duration of zero signal before muting triggers (x =3D 1, 2, = 3, 4). +:Type: Enumerated +:Default: 11.5ms +:Options: 11.5ms, 53ms, 106.5ms, 266.5ms, 535ms, 1065ms, 2665ms, 5330ms +:Note: Values are at 96 kHz. At 48 kHz, times are doubled. + +Clock & EMI Management +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Spread Spectrum Mode +-------------------- + +:Description: Frequency dithering mode to reduce peak EMI. +:Type: Enumerated +:Default: Disabled +:Options: Disabled, Triangle, Random, Triangle and Random + +SS Triangle Range +----------------- + +:Description: Frequency deviation range for Triangle spread spectrum. +:Type: Enumerated +:Default: 6.5% +:Options: 6.5%, 13.5%, 5%, 10% +:Note: Applies only when Spread Spectrum Mode includes Triangle. + +SS Random Range +--------------- + +:Description: Frequency deviation range for Random spread spectrum. +:Type: Enumerated +:Default: 0.83% +:Options: 0.83%, 2.50%, 5.83%, 12.50%, 25.83% +:Note: Applies only when Spread Spectrum Mode includes Random. + +SS Random Dwell Range +--------------------- + +:Description: Dwell time range for Random spread spectrum (FSS =3D spread + spectrum modulation frequency). +:Type: Enumerated +:Default: 1/FSS to 2/FSS +:Options: 1/FSS to 2/FSS, 1/FSS to 4/FSS, 1/FSS to 8/FSS, 1/FSS to 15/= FSS +:Note: Applies only when Spread Spectrum Mode includes Random. + +SS Triangle Dwell Min +--------------------- + +:Description: Minimum dwell time for Triangle spread spectrum. +:Type: Integer +:Default: 0 +:Range: 0 to 15 (raw register value) + +SS Triangle Dwell Max +--------------------- + +:Description: Maximum dwell time for Triangle spread spectrum. +:Type: Integer +:Default: 0 +:Range: 0 to 15 (raw register value) + +Hardware Protection +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +OTSD Auto Recovery Switch +-------------------------- + +:Description: Enables automatic recovery from over-temperature shutdown. +:Type: Boolean Switch +:Default: Disabled (0) +:Note: When disabled, manual fault clearing is required after OTSD = events. + +Overcurrent Limit Level +----------------------- + +:Description: Current-limit trip point sensitivity. +:Type: Enumerated +:Default: Level 4 (least sensitive) +:Options: Level 4 (least sensitive), Level 3, Level 2, Level 1 (most s= ensitive) + +CHx OTW Threshold +----------------- + +:Description: Over-temperature warning threshold per channel (x =3D 1, 2, = 3, 4). +:Type: Enumerated +:Default: >95C +:Options: Disabled, >95C, >110C, >125C, >135C, >145C, >155C, >165C + +Temperature and Voltage Monitoring +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +PVDD Sense +---------- + +:Description: Supply voltage sense register. +:Type: Integer (read-only) +:Range: 0 to 255 +:Conversion: value =C3=97 0.19 V + +Global Temperature +------------------ + +:Description: Global die temperature sense register. +:Type: Integer (read-only) +:Range: 0 to 255 +:Conversion: (value =C3=97 0.5 =C2=B0C) =E2=88=92 50 =C2=B0C + +CHx Temperature Range +--------------------- + +:Description: Per-channel coarse temperature range indicator (x =3D 1, 2, = 3, 4). +:Type: Integer (read-only) +:Range: 0 to 3 +:Mapping: 0 =3D <80 =C2=B0C, 1 =3D 80=E2=80=93100 =C2=B0C, 2 =3D 100= =E2=80=93120 =C2=B0C, 3 =3D >120 =C2=B0C + +Load Diagnostics +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The TAS675x provides three load diagnostic modes: + +DC Load Diagnostics (DC LDG) + Measures DC resistance to detect S2G (short-to-ground), S2P + (short-to-power), OL (open load), and SL (shorted load) faults. + +AC Load Diagnostics (AC LDG) + Measures complex AC impedance at a configurable frequency. Detects + capacitive loads and tweeter configurations. + +Real-Time Load Diagnostics (RTLDG) + Monitors impedance continuously during playback using a pilot tone. + Normal DSP mode only, at 48 kHz or 96 kHz. + +Fast Boot Mode +-------------- + +By default the device runs DC load diagnostics at initialisation before +accepting audio. Setting ``ti,fast-boot`` in the device tree bypasses this +initial diagnostic run for faster startup. Automatic diagnostics after +fault recovery remain enabled:: + + codec: tas675x@70 { + compatible =3D "ti,tas67524"; + reg =3D <0x70>; + ti,fast-boot; + }; + +DC Load Diagnostics +------------------- + +The ``CHx DC LDG Report`` 4-bit fault field uses the following encoding: + + =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Bit Fault Description + =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + [3] S2G Short-to-Ground + [2] S2P Short-to-Power + [1] OL Open Load + [0] SL Shorted Load + =3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +DC LDG Trigger +~~~~~~~~~~~~~~ + +:Description: Triggers manual DC load diagnostics on all channels. +:Type: Boolean (write-only) +:Note: Returns -EBUSY if any DAI stream (playback or capture) is ac= tive. + The driver manages all channel state transitions. Blocks unt= il + diagnostics complete or time out (300 ms). + +DC LDG Auto Diagnostics Switch +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Enables automatic DC diagnostics after fault recovery. +:Type: Boolean Switch +:Default: Enabled (1) +:Note: When enabled, affected channels re-run diagnostics after fau= lt + recovery and retry approximately every 750 ms until resolved. + +CHx LO LDG Switch +~~~~~~~~~~~~~~~~~ + +:Description: Enables line output load detection per channel (x =3D 1, 2, = 3, 4). +:Type: Boolean Switch +:Default: Disabled (0) +:Note: When enabled and DC diagnostics report OL, the device tests = for + a high-impedance line output load. + +DC LDG SLOL Ramp Time +~~~~~~~~~~~~~~~~~~~~~ + +:Description: Voltage ramp time for shorted-load and open-load detection. +:Type: Enumerated +:Default: 15 ms +:Options: 15 ms, 30 ms, 10 ms, 20 ms + +DC LDG SLOL Settling Time +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Settling time for shorted-load and open-load detection. +:Type: Enumerated +:Default: 10 ms +:Options: 10 ms, 5 ms, 20 ms, 15 ms + +DC LDG S2PG Ramp Time +~~~~~~~~~~~~~~~~~~~~~ + +:Description: Voltage ramp time for short-to-power and short-to-ground det= ection. +:Type: Enumerated +:Default: 5 ms +:Options: 5 ms, 2.5 ms, 10 ms, 15 ms + +DC LDG S2PG Settling Time +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Settling time for short-to-power and short-to-ground detecti= on. +:Type: Enumerated +:Default: 10 ms +:Options: 10 ms, 5 ms, 20 ms, 30 ms + +CHx DC LDG SL Threshold +~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Shorted-load detection threshold per channel (x =3D 1, 2, 3,= 4). +:Type: Enumerated +:Default: 1 Ohm +:Options: 0.5 Ohm, 1 Ohm, 1.5 Ohm, 2 Ohm, 2.5 Ohm, + 3 Ohm, 3.5 Ohm, 4 Ohm, 4.5 Ohm, 5 Ohm + +DC LDG Result +~~~~~~~~~~~~~ + +:Description: Overall DC diagnostic result register. +:Type: Integer (read-only) +:Range: 0x00 to 0xFF +:Bit Encoding: + + =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + Bits Description + =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + [7:4] Line output detection result, one bit per channel + [3:0] DC diagnostic pass/fail per channel (1=3Dpass, 0=3Dfail) + =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +CHx DC LDG Report +~~~~~~~~~~~~~~~~~ + +:Description: DC diagnostic fault status per channel (x =3D 1, 2, 3, 4). +:Type: Integer (read-only) +:Range: 0x0 to 0xF +:Note: See fault bit encoding table at the start of this section. + +CHx LO LDG Report +~~~~~~~~~~~~~~~~~ + +:Description: Line output load detection result per channel (x =3D 1, 2, 3= , 4). +:Type: Boolean (read-only) +:Values: 0 =3D not detected, 1 =3D line output load detected + +CHx DC Resistance +~~~~~~~~~~~~~~~~~ + +:Description: Measured DC load resistance per channel (x =3D 1, 2, 3, 4). +:Type: Float (read-only, displayed in ohms) +:Resolution: 0.1 ohm per code (10-bit value) +:Range: 0.0 to 102.3 ohms + +AC Load Diagnostics +------------------- + +AC LDG Trigger +~~~~~~~~~~~~~~ + +:Description: Triggers AC impedance measurement on all channels. +:Type: Boolean (write-only) +:Note: Returns -EBUSY if any DAI stream (playback or capture) is ac= tive. + The driver transitions all channels to SLEEP state before st= arting + the measurement. Blocks until diagnostics complete or time o= ut. + +AC DIAG GAIN +~~~~~~~~~~~~ + +:Description: Measurement resolution for AC diagnostics. +:Type: Boolean Switch +:Default: 1 (Gain 8) +:Values: 0 =3D 0.8 ohm/code (Gain 1), 1 =3D 0.1 ohm/code (Gain 8) +:Note: Gain 8 recommended for load impedances below 8 ohms. + +AC LDG Test Frequency +~~~~~~~~~~~~~~~~~~~~~ + +:Description: Test signal frequency for AC impedance measurement. +:Type: Integer +:Default: 200 (0xC8 =3D 18.75 kHz) +:Range: 0x01 to 0xFF (0x00 reserved) +:Formula: Frequency =3D 93.75 Hz =C3=97 register value + +CHx AC LDG Real / CHx AC LDG Imag +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Real and imaginary AC impedance components per channel + (x =3D 1, 2, 3, 4). +:Type: Integer (read-only) +:Range: 0x00 to 0xFF (8-bit signed) +:Note: Scale set by AC DIAG GAIN. + +Speaker Protection & Detection +------------------------------- + +Tweeter Detection Switch +~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Enables tweeter detection using the AC impedance magnitude c= omparator. +:Type: Boolean Switch +:Default: Enabled (1) +:Note: Inverted logic =E2=80=94 control value 0 =3D enabled, 1 =3D = disabled. + +Tweeter Detect Threshold +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Magnitude threshold for tweeter detection. +:Type: Integer +:Default: 0 +:Range: 0x00 to 0xFF +:Resolution: 0.8 ohm/code (AC DIAG GAIN=3D0) or 0.1 ohm/code (AC DIAG GAI= N=3D1) + +CHx Tweeter Detect Report +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Tweeter detection result per channel (x =3D 1, 2, 3, 4). +:Type: Boolean (read-only) +:Values: 0 =3D no tweeter detected, 1 =3D tweeter detected + +DSP Protection Features +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +These controls are unavailable in LLP mode. + +Thermal Foldback Switch +----------------------- + +:Description: Enables dynamic gain reduction based on die temperature. +:Type: Boolean Switch +:Default: Disabled (0) + +PVDD Foldback Switch +-------------------- + +:Description: Enables automatic gain limiting when supply voltage drops + (Automatic Gain Limiter). +:Type: Boolean Switch +:Default: Disabled (0) + +DC Blocker Bypass Switch +------------------------ + +:Description: Bypasses the DC-blocking high-pass filter. +:Type: Boolean Switch +:Default: Not bypassed (0) + +Clip Detect Switch +------------------ + +:Description: Enables DSP-based clip detection (Pseudo-Analog Clip Detect). +:Type: Boolean Switch +:Default: Disabled (0) + +Audio SDOUT Switch +------------------ + +:Description: Routes post-processed audio to the SDOUT pin instead of + Vpredict data. +:Type: Boolean Switch +:Default: Disabled (0) +:Note: Requires I2S or TDM format. Not supported in Left-justified + or DSP mode formats. + +Real-Time Load Diagnostics +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D + +These controls require Normal DSP mode at 48 kHz or 96 kHz. They are +unavailable at 192 kHz and in FFLP and LLP modes. + +The ``RTLDG Fault Latched`` register uses the following encoding: + + =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + Bits Description + =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + [7:4] Shorted Load faults, CH1=E2=80=93CH4 respectively + [3:0] Open Load faults, CH1=E2=80=93CH4 respectively + =3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +CHx RTLDG Switch +---------------- + +:Description: Enables real-time impedance monitoring during playback + (x =3D 1, 2, 3, 4). +:Type: Boolean Switch +:Default: Disabled (0) + +RTLDG Clip Mask Switch +---------------------- + +:Description: Suppresses impedance updates during clipping events. +:Type: Boolean Switch +:Default: Enabled (1) + +ISENSE Calibration Switch +-------------------------- + +:Description: Enables current sense calibration for accurate impedance + measurements. +:Type: Boolean Switch +:Default: Disabled (0) + +RTLDG Open Load Threshold +-------------------------- + +:Description: DSP coefficient for open load fault detection threshold. +:Type: DSP coefficient (extended control) +:Location: DSP book 0x8C, page 0x22 + +RTLDG Short Load Threshold +--------------------------- + +:Description: DSP coefficient for shorted load fault detection threshold. +:Type: DSP coefficient (extended control) +:Location: DSP book 0x8C, page 0x22 + +CHx RTLDG Impedance +------------------- + +:Description: Real-time load impedance per channel (x =3D 1, 2, 3, 4). +:Type: Float (read-only, displayed in ohms) +:Note: Valid only during PLAY state with RTLDG enabled at 48 or + 96 kHz. Holds stale data in SLEEP, MUTE, or Hi-Z states. + +RTLDG Fault Latched +------------------- + +:Description: Latched fault register for OL and SL conditions detected + during playback. +:Type: Integer (read-only, read-to-clear) +:Range: 0x00 to 0xFF +:Note: See bit encoding table at the start of this section. + Reading the register clears all latched bits. + +Known Limitations +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Clock Fault Behaviour +--------------------- + +On Stream Stop +~~~~~~~~~~~~~~ + +Every time a playback stream stops the FAULT pin briefly asserts. +The CPU DAI (McASP) stops SCLK during ``trigger(STOP)`` =E2=80=94 an atomic +context where codec I2C writes are not permitted =E2=80=94 before the code= c can +transition to sleep. The device detects the clock halt and latches +``CLK_FAULT_LATCHED``, which asserts the FAULT pin. The driver clears +the latch in the ``mute_stream`` callback that follows, so the FAULT pin +flicker lasts only a few milliseconds. Audio output is not affected and +no kernel log message is produced. + +On Rapid Rate Switching +~~~~~~~~~~~~~~~~~~~~~~~ + +When streams are started in rapid succession, an intermittent +``Clock Fault Latched: 0x01`` message may appear in the kernel log. +A 0.5 second settling gap between sessions eliminates this. + +References +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +- TAS675x Technical Reference Manual: SLOU589A +- Device Tree Bindings: Documentation/devicetree/bindings/sound/ti,tas675x= .yaml +- ALSA Control Name Conventions: Documentation/sound/designs/control-names= .rst --=20 2.43.0 From nobody Wed Apr 1 08:37:52 2026 Received: from BL2PR02CU003.outbound.protection.outlook.com (mail-eastusazon11011060.outbound.protection.outlook.com [52.101.52.60]) (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 3F93F36402D; Wed, 1 Apr 2026 02:42:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.52.60 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011359; cv=fail; b=I9nvitwlkQHuhEvYtvIEwDZgulniIMIPYWWnYylWm6R7qkbNeZt7Gq9GUa4yWaeLVyIXA0FgJdb7j4zHTiOkLSGummcIPnxMdOqT/XbWhXH81gKgXYxDVVaiuheGgy7JVOLFF8V/CO1Su0LipEVefN1+PfSiv6d0JZ0xOozg+e0= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775011359; c=relaxed/simple; bh=rc7WOsvlMTx/Xz4R+vH9nwj1BrfsJ9tT4FSLHmpHY5c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Crh9ec+9lCwe6M29OnyK+1v0Gnxdi461tq9FUiRJqwG7c6LYHFxxLOv2kQW10LFrsaNVqOC8/0FcEidWybPkRxt9528DIG6TdnDxmfPUBOHwguLD7o+GpCWM2xhyHtlL4G0nqSSuBmqlQIV73w4tWbrLTt520Gf7pUs4Yt3zPKg= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=HF/spM3l; arc=fail smtp.client-ip=52.101.52.60 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="HF/spM3l" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=pdOnpE5I1o2oBhvC1ePl2g2twz2R8GM9iSwoUMBpZHR+yACTCOg60leoiHzhTpQpBdxml2+s6iOH2JfqDWltq/+tErwbOIB/i8Gooywmqf0RBQ5zT4T+TlqJTDjbfIdNjAoaHEDSh98yYID22ugi6ycaSasPSRxJdNKOqcnbbffzRWOu/PrGVi7aFTU5HI305SFTrYnoEKr7YLAuRDWZoPe6zu3gp2V0LGS9kjXOIbsqhOgMZhBhd0Sl22Ou9fwuxX5QRvrief+ymydwHypiuHK3ZP/1ckA1WiO82UyNRxYmel4uqCE/izssanIJqOb0xClzHY4TS91H/RpKsXkxnA== 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=7G4Bq7eGoPEmFv6nBU5TZN96ky7FW5IWX8m0IhRXDOQ=; b=k7gfP1OuJhkl4VbY1KF3rShEOcxzmmSzzLZhFSnnD8xd4mBEd42Wjy1zGEvlEgsY5RlC5IZ6x7AkQ5/uPALaYQnhlvv9bFmdEVZyIWOO7X00WHpaZXIIWqnBxbhP554PJbmpgtcPhb3e19X5sho9NnZ+KRDGaQxAxuzyQGTMqckD0gQXMCbTpRAzT1vfNXyE+NfIvQ61DecZe+DYcSDqzPSvklHm07THB7UWDR4+KqNSACN2ymYM8q9hPSC9mu4wfe2Xy7SeExu5lkjpsAb3Qv0lOgBi3f2aGnx2LavhouL4zI1iiXxDFtPEr4QkuRmt2CNRUCKj4QhihA3xli/rEA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.23.194) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=ti.com; dmarc=pass (p=quarantine sp=none pct=100) action=none header.from=ti.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=7G4Bq7eGoPEmFv6nBU5TZN96ky7FW5IWX8m0IhRXDOQ=; b=HF/spM3lJieQCQ4b2let4fEXKImh0p3z38DeoCkUSq8cUm4ENfB8rfMa7C8F63ii1BaGVhhFbpbylez7QqkwxUFUK2hLtvnGJRs7/+M74fQ7DIPTiW/sgObClptB7iLZSG9rkn3jATqOyBUQ9D5bJVMFSkckLO/G6vjq15E+iPo= Received: from SJ0PR13CA0011.namprd13.prod.outlook.com (2603:10b6:a03:2c0::16) by CO6PR10MB5570.namprd10.prod.outlook.com (2603:10b6:303:145::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.16; Wed, 1 Apr 2026 02:42:19 +0000 Received: from SJ1PEPF00002320.namprd03.prod.outlook.com (2603:10b6:a03:2c0:cafe::15) by SJ0PR13CA0011.outlook.office365.com (2603:10b6:a03:2c0::16) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.15 via Frontend Transport; Wed, 1 Apr 2026 02:42:19 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.23.194) smtp.mailfrom=ti.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=ti.com; Received-SPF: Pass (protection.outlook.com: domain of ti.com designates 198.47.23.194 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.23.194; helo=lewvzet200.ext.ti.com; pr=C Received: from lewvzet200.ext.ti.com (198.47.23.194) by SJ1PEPF00002320.mail.protection.outlook.com (10.167.242.86) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.21 via Frontend Transport; Wed, 1 Apr 2026 02:42:19 +0000 Received: from DLEE201.ent.ti.com (157.170.170.76) by lewvzet200.ext.ti.com (10.4.14.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:17 -0500 Received: from DLEE210.ent.ti.com (157.170.170.112) by DLEE201.ent.ti.com (157.170.170.76) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Tue, 31 Mar 2026 21:42:17 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) by DLEE210.ent.ti.com (157.170.170.112) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Tue, 31 Mar 2026 21:42:17 -0500 Received: from localhost (mz02jj9v.dhcp.ti.com [128.247.81.246]) by lelvem-mr05.itg.ti.com (8.18.1/8.18.1) with ESMTP id 6312gHT93899137; Tue, 31 Mar 2026 21:42:17 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH 4/4] MAINTAINERS: add entry for TAS675x audio amplifier Date: Tue, 31 Mar 2026 21:42:09 -0500 Message-ID: <20260401024210.28542-5-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401024210.28542-1-sen@ti.com> References: <20260401024210.28542-1-sen@ti.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-C2ProcessedOrg: 333ef613-75bf-4e12-a4b1-8e3623f5dcea X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SJ1PEPF00002320:EE_|CO6PR10MB5570:EE_ X-MS-Office365-Filtering-Correlation-Id: c706e9d2-6392-488b-8efc-08de8f984b7a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|36860700016|376014|82310400026|1800799024|18002099003|22082099003|56012099003; X-Microsoft-Antispam-Message-Info: sf3sy+ndINQxeMUjC2IMQOAgoo6L74Z2z8UeAJC4J3fe17viZ6MLph73WiDOLiocF8j5RLlo9GMF39U6ZSo86Wjr692kDT4ZV0sh+b2RnPujiSfILmrkTmK9XPwXUaIe6h66ktIHNcy5Hywf9HMqQsnoVRWxKPim2urnbOieDqZh6BO6F64rKZPqXz6Wlwy84XZ4sAkP0cwN2ekir70TrHa1X83BEQwYcs8oeo6yVd6NkhhfTvp8EbCWY3XZtmggRaE/JlnRo5nzxHC3nVq8MV3uTpKKD38JN+jWkOI52iP9klE5CQQ3vDVlzpehFR0XhjNo33I6+ErOZfKY83xoZgd9BPDPvuiDZJ9nnel44Qdq/iCWvBd8BcgHIcD7dMhtWThl6Fw6F9EKRUwSuMpYlq4/t0YqSUPeOEYHkR90buf8N3esiY40ecRbhXI9STqmgdDSisGK0bVx7SchdBctQkP9SGwADbDJ5ja8YUVCy39BisK8siMVwArlIw4M7iERyQBQidnoi1PbTtCbNt0VFP7apdywq1jZUXoKXIbFVkU1OgewczIXBKXCHRSZRYwPgYHfhgcpMRsV6QtAKhWAFx0lKk26CUn+8XVsKaCU+IoEqMsZCQCWwcVCDHEYY/8fmHit5L12EeElzWkSeqKuRwHuebjiogTbAXwDI//bfZq0wN39WSyAqJIss/18Cxupvj48MWXl2+cAMNgF1cDRNdR4HJO7gEt9tRTbv09zpf0cA9BiBIPiEv1JyeL/rdUT79LiMbrsqV6a6FX5T0snqg== X-Forefront-Antispam-Report: CIP:198.47.23.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:lewvzet200.ext.ti.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(7416014)(36860700016)(376014)(82310400026)(1800799024)(18002099003)(22082099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: OjI5Mmd9WQbaD861Xvt7kgSPSekBzkvMZNBn/kwwxYjSipa5+9TrKr+1OqI8UnnXVRoUxg+uGSCr9uzqU4kYWLksBK1jAKYr+dppn2+BAcWDh9a224tmwLyYOJJdb1NT3xClw09nSbCl0ruoor8CArEs1b9FCd1T20ndHKnsR+btTihHYx4ACMf75mjMlheU5Y/+sYIcnI9hCBETt/q5fzflS5Kx+uL9G4PJnKGUAaLjdk5FQtIB+RAG5nDAOBtKq2wtEfOh0njAkox3JzJbR81JZQAS+O692mGs6JvEIaWNbxkpYRS3dBrgAt3nCTjJ2+KR7TKikx/LTe8BViPNPC1IN9R11Xf3KmRfsA3+Q+HD9bBBMjTGaaLDHMU5SuW//9LQG44/25GyvLHuS9bzFRfUilNbWBVSlVpLYFaTQLA6Z+vS6H5jWFill9eZMrE/ X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 02:42:19.5897 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: c706e9d2-6392-488b-8efc-08de8f984b7a X-MS-Exchange-CrossTenant-Id: e5b49634-450b-4709-8abb-1e2b19b982b7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=e5b49634-450b-4709-8abb-1e2b19b982b7;Ip=[198.47.23.194];Helo=[lewvzet200.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: SJ1PEPF00002320.namprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CO6PR10MB5570 Content-Type: text/plain; charset="utf-8" Add Sen Wang as maintainer and register file patterns for the newly added TAS675x quad-channel amplifier driver. Signed-off-by: Sen Wang --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a626dee5c106..ea61bb439652 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26191,17 +26191,20 @@ TEXAS INSTRUMENTS AUDIO (ASoC/HDA) DRIVERS M: Shenghao Ding M: Kevin Lu M: Baojun Xu +M: Sen Wang L: linux-sound@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/sound/ti,tas2552.yaml F: Documentation/devicetree/bindings/sound/ti,tas2562.yaml F: Documentation/devicetree/bindings/sound/ti,tas2770.yaml F: Documentation/devicetree/bindings/sound/ti,tas27xx.yaml +F: Documentation/devicetree/bindings/sound/ti,tas675x.yaml F: Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml +F: Documentation/sound/codecs/tas675* F: include/sound/tas2*.h F: include/sound/tlv320*.h F: sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -26215,6 +26218,7 @@ F: sound/soc/codecs/pcm3168a*.* F: sound/soc/codecs/pcm5102a.c F: sound/soc/codecs/pcm512x*.* F: sound/soc/codecs/tas2*.* +F: sound/soc/codecs/tas675*.* F: sound/soc/codecs/tlv320*.* F: sound/soc/codecs/tpa6130a2.* =20 --=20 2.43.0