From nobody Fri Apr 3 19:30:05 2026 Received: from PH8PR06CU001.outbound.protection.outlook.com (mail-westus3azon11012036.outbound.protection.outlook.com [40.107.209.36]) (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 5BB723CAE97; Wed, 1 Apr 2026 22:32:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.209.36 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082787; cv=fail; b=nbK1fMR7E3Yduyxma3YQYkUTGRRfDfsMiyjvYG/UcbAVwMjtX8bDnNVd7QwIW6Tp2fNW1cMOvSvXvySJPTbRZgr0L9PX6N9kTJzBlbs3Rvssjb9z5klKbOtx4t0dr4n+Z3JBn+rdGNbYvuyJAkXoqj4OkLawNq0vek73M8IpF1w= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082787; c=relaxed/simple; bh=JuHd2GgdK2HSkTZZfPjM1XvwWEWf8MsDnvE2quVKkmQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ca6pPPWjepyuL1KcYiqhTy5jtZumAcVe19aijdWThetzwtcbsBvKCtaDzW0+gidi09yy3nbex+FMI61SZ8Rn0tcDJEdn84j/FxJJdrb8Z5s3hCbbjcoyoXThflK8m5VwcYMUihPjU7C7AnvGeliagBm6JEUdWlbGYSetkArRRtQ= 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=JoZKiUZB; arc=fail smtp.client-ip=40.107.209.36 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="JoZKiUZB" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=qJqVpX/wLRp+ukjMriP0RwVDtoBzOGCILx+0eOTFdgHDwwXpUAvjjoV8brpJe8WA3AqN/bD2E3CmvqYOS2jbkJAph2eyGtG+AipnHuQmvWJ1x47SGrqOxGPBJNXaEnUK6oj+e/RFtEhBGNDYColpbDHkOwtUi7k5NlWS/3svD9IlzBN57817QLHSjtgjwuc/w/nkC+JmgMr1clsS/kPd9jaayiqhE5tpQMXlW/kCNGYJ99kiGpSgCpfcnxFagQvZL4q8uxUq8QS2vlWkz9/zNgTKWqmp4rfeaZL0B+4jNU0fRttYhoeqeqDWJ1MqkWg5e+5AUCM1kRSLWGON28kQmA== 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=TxjagLHf+v5F28jTS/fUFEqNaI98M910ZMQ7PXocd7F9ancYSDdXsSbsQrfkpCOditYF5NVpOZ36PTcFvZQAg9zWZImDg8u5fDHIQOtQTcHltsWU9OGkbM9xvwZuDdun+Z7yRwbDpARIIvVLieeSCT4JBuTaKr6Uq8/Si0Mrwi0Vb9N8RhQu8I6rfYl/a2wtKyYd/nW4OeRvVDblVw9AChsqRUOj8LbV5AYlU/QM5t+othHEJEQW2lEpiUwNA+T/uaOYGlCRaL5SVF4R6z2r2/adc41Up3thiuF3GRWi6FP02ODSVI6zLT+b6gV8ZXcNKazn/NEF5/bgYz3FQKzcrw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.23.195) 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=JoZKiUZBELUPXtiwzEJEr3wI1r1i93PMysVO3Q0IlOnpkeL62kWFEu93niwFZ5CCSywpLSllILnLAgcfH8PkC3OWGf44ovu8x+NlffoQjkd19Ykd9n6LLdYnu4kwxiZFRfynxgJbGbhN5KQXe/82IVFfUIgIBgbEYJF02clrnd0= Received: from CH2PR07CA0044.namprd07.prod.outlook.com (2603:10b6:610:5b::18) by CH2PR10MB4117.namprd10.prod.outlook.com (2603:10b6:610:ac::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.18; Wed, 1 Apr 2026 22:32:51 +0000 Received: from CH2PEPF00000146.namprd02.prod.outlook.com (2603:10b6:610:5b:cafe::62) by CH2PR07CA0044.outlook.office365.com (2603:10b6:610:5b::18) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9745.30 via Frontend Transport; Wed, 1 Apr 2026 22:32:51 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.23.195) 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.195 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.23.195; helo=lewvzet201.ext.ti.com; pr=C Received: from lewvzet201.ext.ti.com (198.47.23.195) by CH2PEPF00000146.mail.protection.outlook.com (10.167.244.103) 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 22:32:51 +0000 Received: from DLEE213.ent.ti.com (157.170.170.116) by lewvzet201.ext.ti.com (10.4.14.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 1 Apr 2026 17:32:50 -0500 Received: from DLEE214.ent.ti.com (157.170.170.117) by DLEE213.ent.ti.com (157.170.170.116) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 1 Apr 2026 17:32:50 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) by DLEE214.ent.ti.com (157.170.170.117) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Wed, 1 Apr 2026 17:32:50 -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 631MWoJ41351051; Wed, 1 Apr 2026 17:32:50 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH v2 1/4] dt-bindings: sound: Add ti,tas675x Date: Wed, 1 Apr 2026 17:28:42 -0500 Message-ID: <20260401223239.1638881-2-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401223239.1638881-1-sen@ti.com> References: <20260401223239.1638881-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: CH2PEPF00000146:EE_|CH2PR10MB4117:EE_ X-MS-Office365-Filtering-Correlation-Id: 3d1d5150-cd34-462f-d574-08de903e9c03 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|36860700016|82310400026|18002099003|56012099003|22082099003; X-Microsoft-Antispam-Message-Info: JNhsh7Is6yjXfi98gfFp8I6jLtw30W/AsBNJz1XxJWnU0rbt9722azVhl10vzLvaFr1zJylWFFIl91AXAjwf9r2KRuZlFcpFYqfyOL3cWZn+9sleMNWDU5t2rXMjpXsHYtGKHj2LMSGAK8ZOh6fEFcTybNOBTSBmt9Kj8dSdFAnz251Xh6+ov6g9tiem6kmrdotVOarLMpHoVAL6Wr2jHgtGwgG8WYc+g7tW9we8m2JO5DJDCmVaFjJ1mBbMCrxAp19xk8C5NaXqt1hdm562AUS5xCsn0f8ueJKSpxGwkQZDMmdn8ugaexJmcs2HwALsO9z9ooZ9s48Bwjuhy2mziSGnQ4ikDE4m4NhN2gj8djmynk/cQJHnOWSPK406bePTx/Y2jfckYeRQb2akFXXiBbWIKt1dG3ggpNiU1XuloYWS8wC8rVm4P6/t9P6XxZWy6BDKe5T+T2vZvBFqOB6Zq1RCdc/nDlnFKmSpMQhYTl3EPc/IFhEpj7uZOw66jyfOJA5kJsJJ2AaU4T+1mHEFs8QyYqMWsJrTcaqj62LCaI054MIbUmUw0onEZFiJu4sN+7K4sOzTr3zinQMpaFiQJfAUi0xsOBL43FsDWvUZ+cYp60jZcWJ7fsR6VeUN7FiD1ds+HOL0Sona0xORPWuqba4GmYty4+/J6mX09W0i5QVpvSbyrleI5inMulAN74J2/Dhzip+mhE0nxtmZq+BuUDE/cK/LyA4zI3CS3pYR2RI= X-Forefront-Antispam-Report: CIP:198.47.23.195;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:lewvzet201.ext.ti.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(1800799024)(376014)(7416014)(36860700016)(82310400026)(18002099003)(56012099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: k2EydAvCs2tBjLsOsWVdRBUYgl0GREFZRr9cKJ20wACwbeibBerPzG5QG1dHHM1QYaFsKRMipjEaEgGojNC75KjNwjo/H1JyHDVmYi6TazxW47cL51CmR6pSjscvjdizQV93ztQVHQQZdHzZpE6F70dsj4vGcpTeL8QmzO/QOcGxyOCbe1KpxjWdvf/edWImb9eEVbQojCua71ZXOOakFq8mfpVDWDWl2rzgIyXaZ+wcShaFVmJ3RMQ48Z2/6EQ4pcnPkouUvvDIST1MMQ05r8v5zwuftVWda6EN+g+Hk3eJyqecyo8l8N1YE7YSmhS21yiztbR0wDL8XHwYHTNCMbp71YFFF0b+l51/d3ffcB2Wp7ioqVyVTTynY5jsMyfi3M2YGgrv0/lDNXOJbbuUjz2ZZlANNAerFx6JxZTwXyY8+VV5FsY5TMGQofP0mCO8 X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 22:32:51.1383 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 3d1d5150-cd34-462f-d574-08de903e9c03 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.195];Helo=[lewvzet201.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: CH2PEPF00000146.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH2PR10MB4117 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 Fri Apr 3 19:30:05 2026 Received: from BN8PR05CU002.outbound.protection.outlook.com (mail-eastus2azon11011033.outbound.protection.outlook.com [52.101.57.33]) (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 12BD73CF667; Wed, 1 Apr 2026 22:32:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.57.33 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082799; cv=fail; b=VLRTZaPX6HcGuY1jIe3cbBshTwOKSIWP+35R48PT47/ttOjh3legZte7zE30+ArhRBUo3vjO3OO31s/NxS5EwDubzJQY5qQg7+zP8pUx5ydedzokei1YtI7LcWGNYwWOhWtvsBzhu3aK6qbmlPmRXGeDjs10FwoDPVenW5n+2uI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082799; c=relaxed/simple; bh=kk3Dd+EX/yJXNrBP8/koAnlBjrVZyJjZ3U7/JAlG+1c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=b1Y7zDoCLhFeIQtLU3pymft6b6hUGFc2AC/kaw+X6IzhT3IMspGjShqYcP5Cxq9hGFVuEB4AbfM4RRlbskJw0QB03iPQL78MXkS7cCCtrkyq/5DQFbujjO47EMW5Q4LtoO5EoeU3xBihwAp4F+etckjP6FVG+TCK+k5jgeou2T8= 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=sWdssCzX; arc=fail smtp.client-ip=52.101.57.33 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="sWdssCzX" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=MKHM9AcyAAyq/NRYZE+IAAV3HnceWz+BaTfgBNiPHhrVfI8EHSpErBzxCeooZ83tT7EHqgFb0Vc0rpXGLCXU6EnKtLXOTDBIur4H4ClkDcJdE0F/bSz/aA3C/0PWnl/xCFyP0htqzwyZ6mbEDCbyKKfznP7QmHTc2QokRhqfOnRk8ETwxFkZxkyad0lBiwNQW3Kk1b2J9X01Q0vJF2Z0Gm6s7dE8Mu60kTxWeem6TTX6o11J63ZMMww7H9rryTSLHsVxjjWVvrBgIh4VsnqLD60Zpr9teegUWsCv+bcbVQuFcsKRMEvIRFT0UtWBOeSUs2qvGGOKlVJEmUQZWUR0Gw== 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=thDou9imOxAQRKZOwMAaYvP+sdt+dmhA11WtOZ2WjX0=; b=VU9nQBOZW5nO1hNw5YcPqzY9K/KGS3CHDIQP+JpuAYKFPG8AwrqkajoV+gXvnY/zpJW2sfwKD/HO+BIO1ehi8LitYLvAz34Ly6cFG7VOM2iHuEaGMiizbxoQSnJHMCqhF9OAOqbhkgbcL/GDrt1yhoUAgtQ8y5yrxXziwrRVljD7235ql236EIO3WWSQ+cdh1haG0bDbjN3e9Chst0Vs8kx3IBgbCBPnh7l70jszigaCTk0d9dkCEHR199VqsWn86XX9li8DbmOW/zQ7oXvXhmx40ZScJjmLu4QnCgEilqhUr2Gs4pZvWhN7paGyZ/+jYvxhkWGqZO+WH5VdVkjozw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.21.195) 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=thDou9imOxAQRKZOwMAaYvP+sdt+dmhA11WtOZ2WjX0=; b=sWdssCzXkHVEPHxtEZHeTqj2AWL/w33qhiPNHAyuCdSrqhDp0RibEifBqLvGUQ7Ts/xE56oesS07f8cninvPwkWKcJWmSUR7Mk39KSLSz/eLn3O38JBe3Cl0LbwFiHVjIrzjsHrY6u91mUSzq7X6nqXvhtpAbi/ut/WRrdcIP8o= Received: from SJ0PR03CA0087.namprd03.prod.outlook.com (2603:10b6:a03:331::32) by LV3PR10MB8011.namprd10.prod.outlook.com (2603:10b6:408:28b::6) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.28; Wed, 1 Apr 2026 22:32:54 +0000 Received: from SJ1PEPF000026C4.namprd04.prod.outlook.com (2603:10b6:a03:331:cafe::d9) by SJ0PR03CA0087.outlook.office365.com (2603:10b6:a03:331::32) 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 22:32:53 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.21.195) 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.195 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.21.195; helo=flwvzet201.ext.ti.com; pr=C Received: from flwvzet201.ext.ti.com (198.47.21.195) by SJ1PEPF000026C4.mail.protection.outlook.com (10.167.244.101) 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 22:32:52 +0000 Received: from DFLE212.ent.ti.com (10.64.6.70) by flwvzet201.ext.ti.com (10.248.192.32) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 1 Apr 2026 17:32:51 -0500 Received: from DFLE215.ent.ti.com (10.64.6.73) by DFLE212.ent.ti.com (10.64.6.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 1 Apr 2026 17:32:51 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) by DFLE215.ent.ti.com (10.64.6.73) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Wed, 1 Apr 2026 17:32:51 -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 631MWp421351075; Wed, 1 Apr 2026 17:32:51 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH v2 2/4] ASoC: codecs: Add TAS675x quad-channel audio amplifier driver Date: Wed, 1 Apr 2026 17:28:43 -0500 Message-ID: <20260401223239.1638881-3-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401223239.1638881-1-sen@ti.com> References: <20260401223239.1638881-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: SJ1PEPF000026C4:EE_|LV3PR10MB8011:EE_ X-MS-Office365-Filtering-Correlation-Id: 15b23ea5-6cab-49de-ab92-08de903e9cad X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|1800799024|36860700016|82310400026|22082099003|56012099003|18002099003|13003099007; X-Microsoft-Antispam-Message-Info: YBiGLKJbCWUdxuXUEAa4/EITKtmJsFMV/NmXpIsaUpwlcrf3cjnneZNJw4UzrtZ4t8Qim/p5pvraMbgIVJPPu+Ak7OBPA3259Zlg4Wrs+X9nRoX8ynRiwArqu/gpw5034dcj0FpB4DwUNUq4oOcHhvHN6Nk9sFK56Ps3AQ0Uo+nTlzif19pxkDUjflLfzA2l80TB3rcSvBy77FfrL38txq6KQyBf+Zp0epR5pA9Mb59mCIcN0RmYDTeAAdZOw7ktzEzVrjJ9Ggit23WHg3j/aLpbiHYl+uJQsxNwUh7WC71EOEEdMVSU/b2CUvkoLKLd85mDg55dK2EDaijQNxgLw+zsrflUjwgtOvjSRC5U9ZZyAS7/T3gukycrktwkNKIvrFGNmun+tWLhWkd+v4KA1jAMIrzqa8cxMmWZaGOdaTHLgHqGMte2JgyVoa4sKYq83vaLpp48IyhncF0v1xbb0OkX8bloi/tFXc3XFzgoVTuiLyIQtWg2ul2NWLSU4KzB6fUALtzp9ZhhUVDro/Q5/3EK+D6lPE2p0G7VwYJ3mG7yRVtjGZEVlgaGCmK9roBer14dWaH17tkHyV6eWlLt4ZDHUGcKPmlm2I01wDTsd08dw4/wRFpG4IMGKvstkkaghgIDddQTvlt0Nc8dqPdHPyQegKdy1A28wVPavL5VGEAav4YwAASzqufl2OWf0oOFhPhVGk3p+Ts132oWy0YsUXmHNDsmHDFiqrGgDuYNS8k= X-Forefront-Antispam-Report: CIP:198.47.21.195;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:flwvzet201.ext.ti.com;PTR:ErrorRetry;CAT:NONE;SFS:(13230040)(376014)(7416014)(1800799024)(36860700016)(82310400026)(22082099003)(56012099003)(18002099003)(13003099007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: P0zM1BQ79NF0hq2gICUZgLB5TBTmPtTyGA2aOVkm7INT2H7phsXoyaxilQocteYIMbyiGBVe1OHvbYC+Z9pRfynyAZcy65h1X7Wh6rhfLheWlyLHibyESPkng85p13tS/XU6uKfhLzCglAF89pqST5v9TcDAfWTF4zOant4/BFHJfn5UqFuxVAlbO2IuPLiytnPjj9kryqflNSkfLbScy7aBUePScJVRi+PjpP2qmMi8dH60wibGRpZE1XwAWqWpB+oCORCdq77+396mh68hHt+I7MbZ7fw0WhVQS35t1wFf0tqhjp0ur6yFn5/yioy12c5cpyeCaqeR9AgcZf1m9pGzz1q6xTgwM0qCb1MXCgbWTlgi/J7MasNao8REgNmATTwZMMf0x1XglovGo6ad0Muz0X8k9pof30P5oL1WuQuPs0rsIiRaMk/xgpCNQ4C4 X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 22:32:52.2787 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 15b23ea5-6cab-49de-ab92-08de903e9cad 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.195];Helo=[flwvzet201.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: SJ1PEPF000026C4.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV3PR10MB8011 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 | 2158 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas675x.h | 367 ++++++ 4 files changed, 2539 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..fc30128840b7 --- /dev/null +++ b/sound/soc/codecs/tas675x.c @@ -0,0 +1,2158 @@ +// 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 const struct snd_soc_dapm_widget tas675x_dapm_widgets[] =3D { + SND_SOC_DAPM_SUPPLY("Analog Core", SND_SOC_NOPM, 0, 0, NULL, 0), + 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_dapm_routes[] =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_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 SLEEP 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_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_dapm_routes, + .num_dapm_routes =3D ARRAY_SIZE(tas675x_dapm_routes), + .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; + + memcpy(tas->dsp_params, tas675x_dsp_defaults, sizeof(tas->dsp_params)); + INIT_DELAYED_WORK(&tas->fault_check_work, tas675x_fault_check_work); + + tas->regmap =3D devm_regmap_init_i2c(client, &cfg); + if (IS_ERR(tas->regmap)) + return PTR_ERR(tas->regmap); + + /* 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"); + + ret =3D tas675x_power_on(tas); + if (ret) + return ret; + + 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) { + tas675x_power_off(tas); + return dev_err_probe(tas->dev, ret, "Failed to request IRQ\n"); + } + } else { + /* Schedule delayed work for fault checking at probe and runtime resume = */ + schedule_delayed_work(&tas->fault_check_work, + msecs_to_jiffies(TAS675X_FAULT_CHECK_INTERVAL_MS)); + } + + /* 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 Fri Apr 3 19:30:05 2026 Received: from SN4PR0501CU005.outbound.protection.outlook.com (mail-southcentralusazon11011044.outbound.protection.outlook.com [40.93.194.44]) (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 4D8593CE49D; Wed, 1 Apr 2026 22:33:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.194.44 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082795; cv=fail; b=heQV/TsWTmaywKbLNjVs8iV0GQdlE/bze86si2BgVup0uxQPnSGsB4hwbiMjAWycQNcPuPECtg4930+PlbDKDmWnx49TzV0at5Z+LCz8umqp5zdibsRNZLtgmyJg5bbhFahRxPEfC4mOQXFccx7uLkX/2JpwZRwXYB1s/HfQthc= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082795; 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=PxjL7hUC/LFD4aml++iiBl443oBfCTWiEYcI47FYRgXnSEJP0tyOOqBocBxEDrZ3HGbG5vWM8H4SFhmTP49RNVlG7gAcvJ3cJXyjgN/oIwGdRx4FIqhNN2dskhnJ0uQfBGYCMNv8n94CEhkEAFObwkcqryGG10QmBnxkICwqRvU= 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=Vf0HrZ9G; arc=fail smtp.client-ip=40.93.194.44 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="Vf0HrZ9G" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=RG4cioTDLwbIIyBA6MzNZLrmUtdbaKDdzuUnrSLvTh8VZl+uWPp7vNFiqeyzGaFAL8RxVDUxdnKu95HAGHdh1zDTuqV5D6FWddhgJHW+EgV67yBR+kOtkegTwhloUTgk7hVitZQ1QWnuNOopkLjgjNfln+z4RyghDHW494YqvftOqOQAApiROQVcc9dlZ+n4DhOjMMTsDrMjf1T3s+5upX0s26hm8fFOJojOPmpPehAtkynWdmOhom7+OkIGtSYkM+16uFZJxyF8cvsyszww16fasK7S21X0V8zRFvdALJfYKkn8JOOM6rJJsFFR5amIcqN/XQKmc5cRo2CIQ2SCbA== 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=EuzsOPQmbwYzA2LGg6JyQotSqXbg5/uz+CZNLzKWSECTArhtgBq+X2eRgGLKjsu3pZLED5s5/imrRrHEZ/757APo+JveEfS0mKLj47Dglbjmhnf+IKNzYBTVYxbbxXMTFWEiB25ZQFcadbHs8AZGgiNYZ0Wdgp11qA8xw6ruuDV/NRVQUlfy1R4AdeltL7aJhrOkDyyeEnaMMKmDU/tyqxZxy8oPO8ozfcDf595M9nAoFMNA77mzVWyAKxwuLExV4M+vpccBr6mSuere5Vqso6/MglyEjjeQ0gnV0+wTiERwhU9nPk2crieN5qiKkuMnfsV9OqemVrPbgkmWi8w2fA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.23.195) 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=Vf0HrZ9GWVcyLvF+wB6TxqNXM7UROG6LPRZmqff/f7l+pN7k0fafzibmw/scH82IDBwJ+6dHTaNgN81n6V/rGdSTCJcxioZKPv6ZBc/X4QWJArb3JewDMVyFFMU/YidG962qnBe6CiUScPiSEgAJB9XNp7F3p5AulgUg80a1faY= Received: from CH0PR13CA0032.namprd13.prod.outlook.com (2603:10b6:610:b2::7) by SN7PR10MB7076.namprd10.prod.outlook.com (2603:10b6:806:329::10) 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 22:32:53 +0000 Received: from CH2PEPF00000148.namprd02.prod.outlook.com (2603:10b6:610:b2:cafe::aa) by CH0PR13CA0032.outlook.office365.com (2603:10b6:610:b2::7) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.16 via Frontend Transport; Wed, 1 Apr 2026 22:32:52 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.23.195) 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.195 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.23.195; helo=lewvzet201.ext.ti.com; pr=C Received: from lewvzet201.ext.ti.com (198.47.23.195) by CH2PEPF00000148.mail.protection.outlook.com (10.167.244.105) 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 22:32:52 +0000 Received: from DLEE215.ent.ti.com (157.170.170.118) by lewvzet201.ext.ti.com (10.4.14.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 1 Apr 2026 17:32:52 -0500 Received: from DLEE212.ent.ti.com (157.170.170.114) by DLEE215.ent.ti.com (157.170.170.118) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 1 Apr 2026 17:32:51 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) by DLEE212.ent.ti.com (157.170.170.114) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Wed, 1 Apr 2026 17:32:51 -0500 Received: from localhost (mz02jj9v.dhcp.ti.com [128.247.81.246]) by lelvem-mr06.itg.ti.com (8.18.1/8.18.1) with ESMTP id 631MWphH887154; Wed, 1 Apr 2026 17:32:51 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH v2 3/4] Documentation: sound: Add TAS675x codec mixer controls documentation Date: Wed, 1 Apr 2026 17:28:44 -0500 Message-ID: <20260401223239.1638881-4-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401223239.1638881-1-sen@ti.com> References: <20260401223239.1638881-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: CH2PEPF00000148:EE_|SN7PR10MB7076:EE_ X-MS-Office365-Filtering-Correlation-Id: 9a3dff39-6213-488e-7f88-08de903e9cea X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|7416014|36860700016|82310400026|1800799024|56012099003|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: 8+yupC01dataCJkbCMImQgfs+koIixpjI5yimVuT2jKY1cH9CpOq3N8M6kIjlV6kflfxWQuBZJeXv//sGhDUCY9A13W/Etize5rkAt+Ip1u8wenbMvaDT7oj9la0ZQmp3cBgJVvM0VswIM/VXearCtwcQigk/i/39TclCEDAHP0dKScYcRxDH8X/BNvW6Sf3898KoCtLO/xyUxMKBUMN5JblPw+hbt2RGzjkTCrIT4fCbbFQEHCxdHDWuGYE9rijDKYXNZ+1E+GbjFMnGrFnNK2ErYb9W7mZ1abcgkFc/E4kzDTxxF13R+VJyherfb6apXzTf9RVPrZuYk+y0WYvrCFJE/AEMQ8GJP/QVRznhnWIcLXYwgmQlBlKZtP5edWOY5qy43ryKpc6I+UU2BCdTrwMc9TspcfwZCDKs84NgmlS5K3ZA0A648b90i5lfb5MVld0l8acEWDByIV2HSZ70VcguVdZCjwko9DtuMrbPZgXxXzhuhqQ15fLJmoRiXYNUEiPRe0ioF/pSHTqOJi8MDm5J+zpXkzheGda9AB0h1s33PIrBwXPUb1eFmBd1ITy7O/aJKkW7IMkw8QXHaWZsdu8Ye7An/1sTcXoNLc17lTOfxljCwB3uAbOHDZqQofn2HnJwXylL/eeQQlsF3hRlDTtyriQFA6NlZNcfw+1ev3Dt4dT/SkKRD69NPGR6KVUjg9go4eKumQncFjGC23YnC91xXxi2VP0CAjZdPhF40TbTTbDkilmmJ0Ro2oH9OrFzWKggZ3ymBD7eoZ/vAjgEQ== X-Forefront-Antispam-Report: CIP:198.47.23.195;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:lewvzet201.ext.ti.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(376014)(7416014)(36860700016)(82310400026)(1800799024)(56012099003)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: /IzMR/X9RM5dRjFZMbqdfdtQa4aUsge+WOH9pji2dp4O5MXqujF4ToONlD+1nOLyVRG7PUYMFJVrU5KwZ8QUCK2XhfnYL1Jf8QfxV85GsaZTxGP6yEfJ0dqfgQgTvm5DSStbUVxBj5DygFofprAEKleWcOXquo44uzlrNeRkFuRk/wy9utKkzr8uVjA7Hbz8T0kC78Azf3NcJoSXZJwjEEIKaBTrbimSIT3tRmrbm7C5Il/i2NJmpo1ACFbj52KIa/dV0z0nwIUReIDyiELqlCX1W8vMATBqDTZ4/t/Zbw2jUwfYqnBM4yTanvZl4QiYjsF7ESxcQIm0UbA/ZNE7iCvI0L5j4SMUVVpOgbSW+DPiGm8Bi6jL/lyRfzeHSTeiMZ9QuGgPwWa5TJ7NoHMcUtYXidouXh/TxZwdXGbaiqRi4TGy7UtE+P+3o4w5z8Xa X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 22:32:52.7253 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 9a3dff39-6213-488e-7f88-08de903e9cea 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.195];Helo=[lewvzet201.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: CH2PEPF00000148.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SN7PR10MB7076 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 Fri Apr 3 19:30:05 2026 Received: from BN8PR05CU002.outbound.protection.outlook.com (mail-eastus2azon11011001.outbound.protection.outlook.com [52.101.57.1]) (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 F38573CEB93; Wed, 1 Apr 2026 22:32:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.57.1 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082784; cv=fail; b=STHMge9A1Te2xiAjC8xFHvsx3KVrJec+p+I6qvlfCu1QvfWHQdWadNIKxFeYOHuklVgAqgFwkhNd3gleCPDCk8FXS0ALRoeB02p/+/L+ziyBLzehm+5YgKatUYm6sVltB9Wgb5G2shAxUTg95zs81fvnIxsbfD0OJW8EGGi/OCM= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775082784; c=relaxed/simple; bh=rc7WOsvlMTx/Xz4R+vH9nwj1BrfsJ9tT4FSLHmpHY5c=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=tbN5ozJSPFAhPny4qFiiMfZ1Jzw3DMzPKGDtMIVdpEIWslFNDWCAHv1Rvn54Hc7YNUvWYdfvJEtfxC67wK6r3rAmr+gEURhUi/OpJsZmHaK48jtg8vxAH9QFdd6syAAr7kxDscn7X/kNaK8yNZ1EEB2fgZ6lZC1h+Hl7xodlxv8= 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=FO0ZrJVW; arc=fail smtp.client-ip=52.101.57.1 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="FO0ZrJVW" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=GRwL7pYDeHjPHImX/vpinslZYaLIbIQyUz9SS4B7iZi6hMdz7Bg2rFuErTGB13P1uPmxfi2dvsBL5j172fI70w4SGQ5n4g5fj1gkOkKSykokuy8MXvtYlzF0yhAN6ScWXHnGywloG7uL9UeTIasvDrBqNVdrkNrHTytwYEeMrihCOca1nmwnLsH0a86LXfBoWTYhCfMiAvceZOLN3veeqa1m8nk1w/t3jPbtO17AKCYOjFkMxKj8eiVrczd6i/w10+bMT0iYMDlclObK6i/2OdL4h2mSM6oQWS0hjT3xUyVxxKYcEJFP+Kw1AHuQ97YYwiS7b/7B7+0sVfRZqSuxpQ== 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=Bjo3+YQuEwdqgq1BUWpubDwjCcCGqa5ltmNi25qC7Y98WsPwVF0wykl5Hv2DRtFoZ5cL/sWa3aVJAuWq3iOLlTnrHNPtFv1LS8oUsrPsDQm4adzNQXqYcj+DNhtkJtHLFscMTkzxQunnRM8UUYtDCBh05/FkhQ7cctUbAJBPcV0hVpIUcjNIQFiUbYzGTmbFt//TZ30vEySAd0p/s0bZPsmGT1sjdLkQCIzN18fUnqd5WvOJZF+xxawJuOyTu6xQIrkWiCPFElzyOK4cBZ3EupuM+AgoX7hI0BtUeXQBjpYt7Baa3YNilTe1x8cfCfQarPH8bzoYqHNUWTKiD257uA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.23.195) 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=FO0ZrJVWg0bZ4EZlyRQKA4qDQmLxZzwB2Ftgc2gYESrK4yqOJSDJ0J9C+XeYoBNFVkQDQlvVmDzn7q4lM3bJsS2LhgEvcdk3ghhii+F/FhgPpp0IJxsa/AuvUbBodIzCWk8wI/LXqTJQ0aE+u1X/dkocmwg8RSTAOqONfIAhU18= Received: from CH0PR13CA0033.namprd13.prod.outlook.com (2603:10b6:610:b2::8) by IA1PR10MB6736.namprd10.prod.outlook.com (2603:10b6:208:42c::9) 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 22:32:54 +0000 Received: from CH2PEPF00000148.namprd02.prod.outlook.com (2603:10b6:610:b2:cafe::57) by CH0PR13CA0033.outlook.office365.com (2603:10b6:610:b2::8) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.17 via Frontend Transport; Wed, 1 Apr 2026 22:32:53 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.23.195) 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.195 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.23.195; helo=lewvzet201.ext.ti.com; pr=C Received: from lewvzet201.ext.ti.com (198.47.23.195) by CH2PEPF00000148.mail.protection.outlook.com (10.167.244.105) 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 22:32:53 +0000 Received: from DLEE200.ent.ti.com (157.170.170.75) by lewvzet201.ext.ti.com (10.4.14.104) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 1 Apr 2026 17:32:52 -0500 Received: from DLEE209.ent.ti.com (157.170.170.98) 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; Wed, 1 Apr 2026 17:32:52 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) by DLEE209.ent.ti.com (157.170.170.98) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Wed, 1 Apr 2026 17:32:52 -0500 Received: from localhost (mz02jj9v.dhcp.ti.com [128.247.81.246]) by lelvem-mr06.itg.ti.com (8.18.1/8.18.1) with ESMTP id 631MWqTb887172; Wed, 1 Apr 2026 17:32:52 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Sen Wang Subject: [PATCH v2 4/4] MAINTAINERS: add entry for TAS675x audio amplifier Date: Wed, 1 Apr 2026 17:28:45 -0500 Message-ID: <20260401223239.1638881-5-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260401223239.1638881-1-sen@ti.com> References: <20260401223239.1638881-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: CH2PEPF00000148:EE_|IA1PR10MB6736:EE_ X-MS-Office365-Filtering-Correlation-Id: 9298f095-9c09-4d0f-7433-08de903e9d97 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|376014|7416014|82310400026|36860700016|18002099003|22082099003|56012099003; X-Microsoft-Antispam-Message-Info: kSdrNzbdqPRfzOSRTJlhG3ZERrIIsceRB8zA11UI+IWz8ncpebsKlqARU0QGWP740I3F70SmyCwBsLS0p/6jVZTSyOHvS4BnSXmB1xh5BjUsfYHLahqZPr6tkKjdLw9XVddOQk+f5QKzKCEGFlQdmTvVcFctKIqJH3+cPNV55hgSPOQBje06WKym0gsR06OVOUarmefcvbk73OFY9iK/4fLkNiegnwR8eQBkI4IG9QUoVgrbcStpEqB6IaraToFw83VN9B0X4VjEnqSXpYjGqcUAJEg7hI1I8sCChmj7G8ZTXAMpQ8/QPjDODp9+wc5kikuLZZ6Ut4kVTcDeLrt+we9POQYxp42C/n9bDaFd4oCykAdMzfEnQao+POxnnj/W2FTmlSGUfgolsk44HRrGnlVJGQo7xyDrcboYbaNGSPYmpHi5SwX5WNvk8wsvDU6CZlbJhS5gfm5e6RKk5OD1NeBB6afy1XlMTq+Pfyzv2Q447pFvtC0GJ6758MokNehkJ5jU5SOz105BvlJ6mfJsgWPLektqQIvF8ciGP8M65o5AQdiQGXgxRIj7WRhpZlXq7ad1P84UBhCSFV5deW0sg5CBXjnxX+nxFgkxkUGfhGKTHaIklsF4QX98QxFNrZi+4u5zw4MyRcfrFq6kSg4AerzqyyzSSL2kfXCT0h26vxgKX+4+dsWGYm3kIBg7PadMEXL3OVdHvwG12n1kiqZ/zjuPcjLMwy5HQJkct3jGflBsLmZCmzJi0+2e3oHhZHYWfDNESzgRHFvoYT7lDevKqg== X-Forefront-Antispam-Report: CIP:198.47.23.195;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:lewvzet201.ext.ti.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(1800799024)(376014)(7416014)(82310400026)(36860700016)(18002099003)(22082099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: oCG4jYW1dFuGq4Jtn/q1EWPXPkkq+8ZoQPsUs/OkA7Ki2sUIcClCxONDCiVGFhRHuYt/qE7kb4ZrG6o4Gg+KtEwnY/32F033R/Y2EFqlN13EZzezpPoBFNWfNlZidRsn75ObISOKIjl/MUy42ji22B7gdz9gUrl3S33FuMI/e4rtg+fJq4CiV6YNpRjg4xc+clgHKHv/ojXFcDZyDFCtqWPoLIjX5MHabu+PRWPtATRRuuj8UJbWszq52RvIEu6OUh7rf9RvdF2j14LFNm6KiTHqNzhYeXB6Wd1WGfQx8oevuTGEBnjouH6EvixuDl9aXX2vfZa0Ur0Y/hKqHk50VlToeNAR63BPANXadKdvKJjyF11ots/CBVoV2/rz0xYAcePFIsW1UQ6rUkL88f008zCq2err9lr4hh8mqs8m/5NF3Hw7YcE7sifQSmi2vm5b X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Apr 2026 22:32:53.8606 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 9298f095-9c09-4d0f-7433-08de903e9d97 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.195];Helo=[lewvzet201.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: CH2PEPF00000148.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: IA1PR10MB6736 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