From nobody Tue Jun 16 11:15:46 2026 Received: from SN4PR2101CU001.outbound.protection.outlook.com (mail-southcentralusazon11012046.outbound.protection.outlook.com [40.93.195.46]) (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 A4CA635972; Wed, 8 Apr 2026 05:32:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.93.195.46 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626322; cv=fail; b=SCnCRR82dhyWFaa8K75ORQQFXZZ6PLFru7cFdrLoTdLDepy21lwWmtNlQybVlqSCcPZSoNvf5QCn3ypQGPhXrTdY71bX1CpZZBv42Bk3YivuVUFfKiTMIcv7ec07UedtMjOcbOGdOL90qo3kEVD0tirHOWstqhm4mQnYN5FGd9E= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626322; c=relaxed/simple; bh=+T5gKlplSSxsGckNyMt6P3IeK4u3ql0auaxSNUYdR/w=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CN+dz4mfjivTHUG/1Up7Mv+vVkfXFKz/KGAbN+fuPolRMJD3on4z4kBLuqh6QC7BWNS344aKZw5OHlot6wJmBKtNvfKXvCZ7JyhwQrStGB/vmqKbWfrn/hz0s/uGeUosJGGh11S+0/FgprO/tg7whdtrUjnIiAJlA0EXUvKFBro= 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=e86HRAjt; arc=fail smtp.client-ip=40.93.195.46 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="e86HRAjt" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=Dt2wUhBeT1G+HEZi66ZK3klYuX4VqeWGSOeAtqi2E8doc1WJ4DWKf10bJcw2b9UjmLnljIdSLoyj5nDU7JkZvTQi4mxkCSdIvdbIxu+Wmz9ADUb1yB5PHtXIXYd8Iz9gdIMURz3niQixBNas4AD31KrP5AxuvDbkYNPVscs0RjF83Cxk9Csh46Lr9pAvSGEt3LmklDduzo4s3oPwZ1t7+7Z5vVGTZ/Qt6cy/040YpIGIlvxKK2kI+vcFeQcTFeNlFOiWLXg4QkNw8TrDdwf3JqYyIu4FgTLOP8fJUM4efj2RTbWPeq0+7NXsW1NI5V51fFibWSTkimBArNMhEICbGA== 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=SH03qPbqlnxlPe+jCSikFL7z26LqsJ4or0sn97XVp6I=; b=IuqIHz8iB7kXT4b9I0XT/FAW2xQSoNFVeJ/ar5VuAIbDb+8nqzTSxF8ofIb9x0BIzc65VkXLWdVchaQoTqzVz4MZQONBTIweOr2kmD21JkWYx9Mh5JHQe1LNz+uzcQgl4p3uboPpwDEVDC+xQkfpC5Endak/A0wt2H0AZRI/lEwka7A804PAoRd3t0nphE7/LJpsCeJEI6ObVGtpbMortry9GAjppMCgdbrLJ6qpbIiFXdyTiKa8FSKyn+KnjoXrvHwr7tgqU7XMXrRixr9OhE/EW0tYwd0uoE8ciWkpm+D9waiX6rULRbxCD2tGdZLHEEbGM/IbmFmFGs22eFJcqA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.21.194) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=ti.com; dmarc=pass (p=quarantine sp=none pct=100) action=none header.from=ti.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SH03qPbqlnxlPe+jCSikFL7z26LqsJ4or0sn97XVp6I=; b=e86HRAjtOQzWNMbBV2w1aEEmjMu7b1HV4PjTcDSPArng1VTrR/bvrcxrIKmucXUPRn3WaO4hHbT0EsXRUBt+S751Tj5AVpgOsikXS9FTHQVtgevf2effMJ6e+KCjNg3oKaxajqxHpxqu7Pr/lqeeryEblouwZOM8kGiV/sScy0Y= Received: from MN2PR05CA0033.namprd05.prod.outlook.com (2603:10b6:208:c0::46) by LV0PR10MB997615.namprd10.prod.outlook.com (2603:10b6:408:340::17) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.20; Wed, 8 Apr 2026 05:31:58 +0000 Received: from BL02EPF00021F6A.namprd02.prod.outlook.com (2603:10b6:208:c0:cafe::86) by MN2PR05CA0033.outlook.office365.com (2603:10b6:208:c0::46) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.33 via Frontend Transport; Wed, 8 Apr 2026 05:31:58 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.21.194) smtp.mailfrom=ti.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=ti.com; Received-SPF: Pass (protection.outlook.com: domain of ti.com designates 198.47.21.194 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.21.194; helo=flwvzet200.ext.ti.com; pr=C Received: from flwvzet200.ext.ti.com (198.47.21.194) by BL02EPF00021F6A.mail.protection.outlook.com (10.167.249.6) 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, 8 Apr 2026 05:31:57 +0000 Received: from DFLE210.ent.ti.com (10.64.6.68) by flwvzet200.ext.ti.com (10.248.192.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 8 Apr 2026 00:31:55 -0500 Received: from DFLE211.ent.ti.com (10.64.6.69) by DFLE210.ent.ti.com (10.64.6.68) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 8 Apr 2026 00:31:55 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) by DFLE211.ent.ti.com (10.64.6.69) 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, 8 Apr 2026 00:31:55 -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 6385VtpW1351844; Wed, 8 Apr 2026 00:31:55 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Subject: [PATCH v4 1/4] ASoC: dt-bindings: Add ti,tas67524 Date: Wed, 8 Apr 2026 00:31:45 -0500 Message-ID: <20260408053149.1369350-2-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260408053149.1369350-1-sen@ti.com> References: <20260408053149.1369350-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: BL02EPF00021F6A:EE_|LV0PR10MB997615:EE_ X-MS-Office365-Filtering-Correlation-Id: 7fe3aa6f-fd8a-4c21-29c1-08de9530270d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|36860700016|7416014|376014|82310400026|56012099003|18002099003|22082099003; X-Microsoft-Antispam-Message-Info: OiK1zlCTBlx4Zq3vwcUWWM/0cwnKyqzRxG7IXyoKIw9ADB84F7Jnqe1MnZz6EcVyPJx9+zyg4QnylbLbOKO23ZcjZKMq15atRSkPh/YyeHoR4C8atIY6H1vnf+XWYcZ7gCrLC7UjCZwJo9xXNfZOPFJTFVzNg+gPNSErbVvxChX8xxuPd+8+YDx7cFjpcpRZMndBRUxuoFpJZV8bsMPstZ/G5egfByjAyhVZQq9ckuAIrziTOzn0TmVdL25bkFPDUnWPW5Kjz2eeyk6v97rpT4d894BAxhwgvv1BXZc6qCk8+xmM9erOxfKEA8HEgCgCHRF4Bf0Z1oTiHCkM9XsbIQ6DSAT9RL+Ag7HxIpGLIRndA6rlHkc0HqT2QxNCwAOKorzgBGI0Be7uGvr5vKbt4qZ93zxa4IfCPQK84XIJ6jlvFDZuDYkrxgqTwdPineNLagoQB0qNyRriNGztYLPdohs6zIxfhn1zeblyL/VloHv1f34tk9u3GKN76BbOdY5wxEk9SwqSrpHm3LNoxIG/XhlGwxWG66Rldxa/MrnbAlh9dHyT0j6eh+LBlnGebnK6w05QnSiyfIklWQKtu51gh/fhHBAp7TSNGNg/9fPbUQGl1/OvGX4qgskAYjG5lZpnujr83nuLimSDzv4qlG10m+bLUDyOJveHeuC1yPVr2ECWMY1IGM1TdTrNSQoChS/oCU6ku9Fr/5VpnsZG1e2Vt/6kHn0aBdJqF6ro8aeV0vY= X-Forefront-Antispam-Report: CIP:198.47.21.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:flwvzet200.ext.ti.com;PTR:ErrorRetry;CAT:NONE;SFS:(13230040)(1800799024)(36860700016)(7416014)(376014)(82310400026)(56012099003)(18002099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: H3CfShKY7Wb0SfQSLaW+m0yscYompB445MJFxVmXXNQO01FEo1ScNTJlRC2F4xFmDmh/zbR6jmcIWDdLDptw7cIHV19BVjMYjsXCKtXE/naho+DN5G1N4QsR722wO18+glId5dELkE3x0OVbJEQtSifXtsMv/8nDq959ccWms6fYytepsS3oDrKjqrvdwZ8Ra+oD1BjdX8tbmZqB8IGuXXuwIiXlDnGE2QmjiahXGIUQYJYxZbfM70LNXNC8F97RdqTey7IfP0zMxY8PwlKt8vyqcgcs7NUIUrL+xjnnTz59bvTFhFat4kJXo3ib58eHJ5wAZ6j23ilfspH0whp4AekVBufADdOcvYyNz8sZIz2Pzwmd4IY+1tbXr9+hlXF5A2yLrr8GX01eQtb558c7skOFYRpi7IV8K1MX/SyKiLDWBdqv9HV0q5oVYwbo8wUY X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Apr 2026 05:31:57.8110 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 7fe3aa6f-fd8a-4c21-29c1-08de9530270d X-MS-Exchange-CrossTenant-Id: e5b49634-450b-4709-8abb-1e2b19b982b7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=e5b49634-450b-4709-8abb-1e2b19b982b7;Ip=[198.47.21.194];Helo=[flwvzet200.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: BL02EPF00021F6A.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV0PR10MB997615 Content-Type: text/plain; charset="utf-8" Add device tree binding for the Texas Instruments TAS67524 family of four-channel Class-D audio amplifiers with integrated DSP. Signed-off-by: Sen Wang Reviewed-by: Krzysztof Kozlowski --- Changes in v4: - Corrected ti,tas6754 compatible with a fallback of ti,tas67524 - Corrected comment spacing Changes in v3: - Renamed ti,tas675x to ti,tas67524.yaml - Removed tas6754 compatible instance - Changed pd-gpios to powerdown-gpios - Cleanup unnessary "|" formatting Changes in v2: - None .../bindings/sound/ti,tas67524.yaml | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ti,tas67524.yaml diff --git a/Documentation/devicetree/bindings/sound/ti,tas67524.yaml b/Doc= umentation/devicetree/bindings/sound/ti,tas67524.yaml new file mode 100644 index 000000000000..812a4d39e2a5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,tas67524.yaml @@ -0,0 +1,280 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sound/ti,tas67524.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments TAS67524 Audio Amplifier + +maintainers: + - Sen Wang + +description: + The TAS67524 is a four-channel, digital-input, automotive + Class-D audio amplifier with load diagnostics and an integrated + DSP for audio processing. + +allOf: + - $ref: dai-common.yaml# + +properties: + compatible: + oneOf: + - items: + - enum: + - ti,tas6754 + - const: ti,tas67524 + - const: 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. + + 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. + + powerdown-gpios: + maxItems: 1 + description: + GPIO connected to the PD pin, active low. Controls the internal + digital circuitry power state. When asserted the device enters + full power-down mode and all register state is lost. Can be omitted = if + PD pin is hardwired or externally controlled. + + standby-gpios: + maxItems: 1 + description: + GPIO connected to the 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: [powerdown-gpios] + - required: [standby-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"; + + standby-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 Tue Jun 16 11:15:46 2026 Received: from DM1PR04CU001.outbound.protection.outlook.com (mail-centralusazon11010026.outbound.protection.outlook.com [52.101.61.26]) (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 1DCF33BB4A; Wed, 8 Apr 2026 05:32:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.61.26 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626341; cv=fail; b=Od92xexhuIs5Ci0cegnsvCV4jHK5AVu10OIpmooezpN/dEpPgPt7DDQJ3LrMAw6GeObwmgp75kuCPGFgJBQ7qT3SAERCeECaC1rFBzLi+COg8OBPLcP0kwhWfDHC3+ipZwlcsADad0g2WYb7dQ/F+/zb30QxIfWtDq/8YfbXXK8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626341; c=relaxed/simple; bh=Y5XcrMldHYWMHCANEzHrTqmnJVIzBRGjwkVfHKIkmuM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DxbOaRmsjB0dmmUgZbE94adIFN17a7Zmgf6l32lsuhARIH3On9/4tUbpTzSlDGqekYitEVfaHAXDnt8v4YZxNLQXQ0qSGgQrGmM1b63gZxdKJP41NXILLcUAntgvVjTom5GAb+2jzUdFELa0ktT1b2xyQNbaXHRTznQLqzbm4VY= 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=BZ1jmeyF; arc=fail smtp.client-ip=52.101.61.26 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="BZ1jmeyF" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=EWqsv1pxSwtgjqiBcALVooB2yQ5hqjIu/6som0RH3dluU9CJxj/9Y3aQtxEsCBS8c181ChVoSGRL8XIiPXNFMjnRh1gr9f1gP04lQ5BLyEQfbsDvzbmcKtVQo0+TyYkxpzqzzEajHotsHvvwfTH+Oms2XtO/yil+SxyAe74ve8OORlyf0CgSBG0yxI1E4GUzLuQh1kCG26ZFWOEEERRd9W9QCE1Q0o4O+QhF06G4j/Dyb3Jikz4WKjgZY1BIglMxEv/Dt6owtGxWPeZRooJDFCUT0wZO3974KZ86ozgDdj9v6giXZDVtyRVWRBEinqFjt/YDhtE6uXtpwYSbK27R2Q== 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=GZ4LdiYuo9kdsEANNEqh5KwSQrWnrbYjl7EIPgXIK9Q=; b=rjgS5AW99TZJNmDtX0TJILIeOAw5mJRXFsJC54+8NxVGbuD88JebL8L2oAz4NRSyQtRE9LsnJpKwZF+W+OqyHRqjZrToh1zcX6j3c4WG9NF0F0JMOZLQCbZgfBwkY8EyId3DQ80mHhnvSyqcj14Koree11QmVgg/7sDio1GQ5pc/Q5eb7CSRIreNIWQE2ochnhP2ArcdDNFFEI9l9nenQ4RX96fXUu+H9PpaiLiyzlK98m/iMor2NwrG4/YAGqyJ23mLiQs3tYljttnrkQuTObvjTbPNpSOOOQzfe5kB6ebWTou2nM3xeEFouCyFc6+ZMFhEPvllPvmpWQvYUyaPSg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.23.194) smtp.rcpttodomain=vger.kernel.org smtp.mailfrom=ti.com; dmarc=pass (p=quarantine sp=none pct=100) action=none header.from=ti.com; dkim=none (message not signed); arc=none (0) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=GZ4LdiYuo9kdsEANNEqh5KwSQrWnrbYjl7EIPgXIK9Q=; b=BZ1jmeyF/JjMPGXwHhNlTqzluVUuAbtXpdgjYbKTkJ7owm3+1SRkpNBu+4qsDeeYau+Bmv6wZLZMTdcqueGwS4gppi24Y5CdHVO0dQl1ovv4Nfwugku2NRLCq4fxgD+d8h0Fa68A5NB7m4Q1xfep9tXZClWAgKlRTHEJRjo4/qY= Received: from DS7PR05CA0027.namprd05.prod.outlook.com (2603:10b6:5:3b9::32) by CH0PR10MB4969.namprd10.prod.outlook.com (2603:10b6:610:c8::18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.20; Wed, 8 Apr 2026 05:32:13 +0000 Received: from DS3PEPF000099DE.namprd04.prod.outlook.com (2603:10b6:5:3b9:cafe::e3) by DS7PR05CA0027.outlook.office365.com (2603:10b6:5:3b9::32) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.33 via Frontend Transport; Wed, 8 Apr 2026 05:32:13 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 198.47.23.194) smtp.mailfrom=ti.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=ti.com; Received-SPF: Pass (protection.outlook.com: domain of ti.com designates 198.47.23.194 as permitted sender) receiver=protection.outlook.com; client-ip=198.47.23.194; helo=lewvzet200.ext.ti.com; pr=C Received: from lewvzet200.ext.ti.com (198.47.23.194) by DS3PEPF000099DE.mail.protection.outlook.com (10.167.17.200) 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, 8 Apr 2026 05:32:13 +0000 Received: from DLEE215.ent.ti.com (157.170.170.118) by lewvzet200.ext.ti.com (10.4.14.103) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 8 Apr 2026 00:31:55 -0500 Received: from DLEE213.ent.ti.com (157.170.170.116) 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, 8 Apr 2026 00:31:55 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) 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 via Frontend Transport; Wed, 8 Apr 2026 00:31:55 -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 6385Vtag162442; Wed, 8 Apr 2026 00:31:55 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Subject: [PATCH v4 2/4] ASoC: codecs: Add TAS67524 quad-channel audio amplifier driver Date: Wed, 8 Apr 2026 00:31:46 -0500 Message-ID: <20260408053149.1369350-3-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260408053149.1369350-1-sen@ti.com> References: <20260408053149.1369350-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: DS3PEPF000099DE:EE_|CH0PR10MB4969:EE_ X-MS-Office365-Filtering-Correlation-Id: b9253266-2168-4b5d-2906-08de95303044 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700016|376014|7416014|82310400026|1800799024|56012099003|18002099003|22082099003|13003099007; X-Microsoft-Antispam-Message-Info: QWkCg+YeqLZQTv/+eZmyifwGJHVHZRWkk1jua5eR3vV8AXnGSHnYys9EK0KGQsULn/tMi4ac4KXdkxlaJecUcTUW8ZDelAtggmVaPF1gDhcNuHn83QAX3S6yzyyvta1E2idD2unrYFbC2+SLnzsclAEjTT6nruk05W8tTyYZ2bVh3l6+xMaoSw+5VwLAdgdXBOVCpxato/8cMQt1ieCNvrvQ0evxRLhWI2Lqn/DmIqGxS12m8mHOitLyCosyBvuAjuAMpntF09qfmYlUpk8UqOPbZF0mnIGEjikmUC6jzHcFY0b5i0klHbIh1q6p8uzcvUpEbaui3ftEdHYucT3ggpTfEDwElX3EEki99T9exNG3oC45vsETEL50EYRZUWjTQJu+L7p34TzJYhDZE6X7h4bVbzKo9NIihT4Ds+sbyCGnDrZFkEVCPahiWzC2VEetL2dX2g+S1Vl3KjNrZqLrTetJQxgLEJZRFCNrlGUo4EFRpieDG3+SbggBrhMrPami8n1u19rxg68f6fzohz9ECa8UJACl5SnqM2Xegkxg+tG2r1kGgmLgzK5ogMUFFW2szqie8XP+05zuI0rpR07DV22MpAmr4F/y39ci2QudelPknvu7JwTor3aKEISyq8jRKEIS9f1AZ0DcrtCnd726e5pjkChvBKp48FDgWRAlKBHeDXG8di7nCgJZV+Jf9pPXct9MX3fD5WVN4fXaG3GLmQvF5YuMyWQFUALZ+VfB3Oo= X-Forefront-Antispam-Report: CIP:198.47.23.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:lewvzet200.ext.ti.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(36860700016)(376014)(7416014)(82310400026)(1800799024)(56012099003)(18002099003)(22082099003)(13003099007);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 8s9ajYKwBayahIyavI9FOZjd8cSKdLRd1QCvzOduXDY1KWqZfpGIbs6MCPNsB70OiFmaMY1Fkl4gwLmlj4vWRRQ/0VjfmBtavOdl4/ZE/haEQxp2L/tEZfTL4feSMdlB8rw2Z9M66qdAx6eU6ReOF0jfpuoMk5TY1KKiEfrhXsuHDulHcUSRXAdvXWEKPpPnLHDqQ+A668wLSE46KGliK6FyDU6QxkGku1rl/5b43PD67uGgaHFu+B0SRd/kKIbLPQc5nS1Zj96FOUf0PjcxsFpq938FRe0e3c3RY1mJVP7wDtu4LEatCys/ENgGypwlXqjfrvTOOvYlmsyc9cJPa4xXWUXoAeqnYSKhz7072lZKa20QQt/7UXka8IwA7VDyqZbhL95F/dA/Mj34YOP3S6/8VD05VvsLWD4/hh2e11GNOaGFQ+XyRxq8HLhr4H/X X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Apr 2026 05:32:13.2884 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: b9253266-2168-4b5d-2906-08de95303044 X-MS-Exchange-CrossTenant-Id: e5b49634-450b-4709-8abb-1e2b19b982b7 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=e5b49634-450b-4709-8abb-1e2b19b982b7;Ip=[198.47.23.194];Helo=[lewvzet200.ext.ti.com] X-MS-Exchange-CrossTenant-AuthSource: DS3PEPF000099DE.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH0PR10MB4969 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 --- Changes in v4: - Reverted filename change from tas67524.c back to tas675x.c - Removed improper kernel doc syntax Changes in v3: - Use disable delayed_work and re-enable on runtime suspend/resume - Similarly, use disable/enable IRQ on system suspend/resume - Include IRQ_NONE on ISR returns - Clarify _check_faults() which now returns need_clear boolean Changes in v2: - Remove redundant DAPM event function - Move IRQ request past power_on(2/4) - Add delayed_work at probe time to accomdate no PM config - Change .set_fmt and .dapm_routes callbacks to the same tas675x_set_fmt n= ame sound/soc/codecs/Kconfig | 11 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas675x.c | 2172 ++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tas675x.h | 367 ++++++ 4 files changed, 2552 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..28a976f32d9f 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,16 @@ 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 amplifier. The device supports I2S and TDM interfaces + with real-time voltage and current sense feedback via SDOUT, and + provides 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..2c40cf1df91d --- /dev/null +++ b/sound/soc/codecs/tas675x.c @@ -0,0 +1,2172 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ALSA SoC Texas Instruments TAS67524 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; + /* Custom regmap lock; protects writes across books */ + 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 9 + 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 LDG 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, + } +}; + +/* + * Enable regulators and release hardware reset GPIOs. + * The device is not I2C-accessible until this returns. + */ +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); +} + +/* + * Write 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); + } + + /* + * Configure fault and warning event routing: + * + * ROUTING_1: CP fault/UVLO latch, OUTM soft short latch + * ROUTING_2: CBC latch, OTSD latch, OTSD, power fault + * ROUTING_3: CBC latch, OTSD latch, power latch, DC LDG, + * OTSD, power warnings + * ROUTING_4: OC latch, DC latch, protection shutdown + * OTW latch, OTW, clip latch + * ROUTING_5: clock latch+non-latch, RTLDG latch + * CBC warning, clip warning + */ + regmap_write(regmap, TAS675X_REPORT_ROUTING_1_REG, 0x70); + regmap_write(regmap, TAS675X_REPORT_ROUTING_2_REG, 0xA3); + regmap_write(regmap, TAS675X_REPORT_ROUTING_3_REG, 0xBB); + 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_STATUS_1_REG, &val); + 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); + + disable_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) { + enable_delayed_work(&tas->fault_check_work); + 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; + + if (to_i2c_client(dev)->irq) + disable_irq(to_i2c_client(dev)->irq); + + 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; + + if (to_i2c_client(dev)->irq) + enable_irq(to_i2c_client(dev)->irq); + + 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_STATUS_1_REG, TAS675X_FAULT_TRACK, + "CP / OUTM Fault" }, + { 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 fault register needs to be cleared. + */ +static bool tas675x_check_faults(struct tas675x_priv *tas) +{ + struct device *dev =3D tas->dev; + bool needs_clear =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 needs_clear; + } + continue; + } + + if (reg) + needs_clear =3D true; + + /* Skip logging stream-dependent events when no stream is active */ + if ((f->flags & TAS675X_FAULT_ACTIVE) && + !READ_ONCE(tas->active_playback_dais) && + !READ_ONCE(tas->active_capture_dais)) + continue; + + /* 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 needs_clear; +} + +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; + + if (!tas675x_check_faults(tas)) + return IRQ_NONE; + + 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, "powerdown", GPIOD_OUT= _HIGH); + if (IS_ERR(tas->pd_gpio)) + return dev_err_probe(tas->dev, PTR_ERR(tas->pd_gpio), "Failed powerdown-= gpios\n"); + + tas->stby_gpio =3D devm_gpiod_get_optional(tas->dev, "standby", GPIOD_OUT= _HIGH); + if (IS_ERR(tas->stby_gpio)) + return dev_err_probe(tas->dev, PTR_ERR(tas->stby_gpio), "Failed standby-= gpios\n"); + + if (!tas->pd_gpio && !tas->stby_gpio) + return dev_err_probe(tas->dev, -EINVAL, + "At least one of powerdown-gpios or standby-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 }, + { "tas675x", 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 Tue Jun 16 11:15:46 2026 Received: from BL2PR02CU003.outbound.protection.outlook.com (mail-eastusazon11011024.outbound.protection.outlook.com [52.101.52.24]) (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 2C15B35B650; Wed, 8 Apr 2026 05:32:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.52.24 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626324; cv=fail; b=Js5rduNwaX0CGOJk2/u5DdnqV81Gq9BdF2P2tVB+qjxG0nqncH2vUlnMmvuDrHycQwKHiap4kMG6oEIh66w/nD6BRhaxu63H8NBPlco0LrPeDnwv/Kv0OSXm3+73XiJyLy/XE0Qw8N1iHipbLmxVVGkS2AY+cJhp0x7L1Br1KZ8= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626324; c=relaxed/simple; bh=pvavECxvXThjAhMYhJDWKMFw9bO7FK8RxIaEVcoi4wg=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=e0k1PGtX768eTwK23bwG/POMBoWRicNTWV4R9cGFwnrLFhdBxhByJAYttlr80TAG8eCMs6/gtBYoAaoAZvJ9PC+d+opQBenyJKUt86Kppktgxp/8dSzuA9xxsquIWJLGbKJKJdlH3eygO8JlKYRiQqFyGgmM9uHc2Xqc1hxMM4E= 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=aUKK+S4a; arc=fail smtp.client-ip=52.101.52.24 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="aUKK+S4a" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=P21AFSUBMPOZNZ9QncD8Cm0ENZHV1JOh4qq+O/ahHoPQ+xW5lOwG8T3a3KNUIGoW2R9viQoQW9ck6ozyzsW8RwBVZ5WxhpIq147adYYlEGzxzXH2v5UhMGwM2luyx3j0foTGlCLIzRThLf5Rcyt3FHogaZfnYdibuiO3cZSS5YVjurrGztGS2BWP6RA+sobEVyuIXAq2sX88se7YPmE9a77YtL5cGMi6+dUuQWxbW0hvPeN4NBISZflXFGYclQSNqOmyDAUNjhbp/ChuvMMs5ednHtYd0xTUGlPUaIkNsY8xr8HMT+UKFegwK8E6vYSjB+ToxY3AYxUcWuqBvX3twQ== 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=7eApNhc2SzDiwzm87WyeHV4AAvX63MvNoPxye3p56Mo=; b=o+9ZipSXBZ3ZspQGu8dmIBHR4kzqetCuET+4fENsaU/nPkop6O8iP8C7LDL8QApkBmjJTI4B6GFPzPSpCqdkGLKomVAe0jMgmy0qw1j/i9f0P6YRMnogSDu90s2eTBdcTH8cCUODcGV5jsOc7qZjWZtBj6U8FflufHpYIojQkvEoQRyPStLsxXAqHfCDiQXuBP3mna78hyCkAPRFoZfXIZQQlTA0c9r5jGgu8r06X++qhKAPyLUdfqO6Lx+VbbNx97AhVi21zEr0UydFrajHytUHyZ3VTM0lSevbbi5FyT/NexQVHy/s/CD63HgJ/wMmAMNf18kWRs60aOoQlv7+Kg== 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=7eApNhc2SzDiwzm87WyeHV4AAvX63MvNoPxye3p56Mo=; b=aUKK+S4aKNsJqV/jhlDZp7IYqyUaOulur5occhiJPH4M1HXk08oOzczwgJLB3fa4vB1aJsiQgYKpf37PJBLkTOeowtt4uV5Cj6XtYsKtwoniqWjJf6eHT6bzU9/NRHUfRTS6blOfiycl6pLqxBNWmsQvigeJCx1bg3d8hK0xv+8= Received: from SA1P222CA0053.NAMP222.PROD.OUTLOOK.COM (2603:10b6:806:2d0::27) by IA1PR10MB7168.namprd10.prod.outlook.com (2603:10b6:208:3f0::9) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9745.22; Wed, 8 Apr 2026 05:32:00 +0000 Received: from SN1PEPF0002BA4F.namprd03.prod.outlook.com (2603:10b6:806:2d0:cafe::cd) by SA1P222CA0053.outlook.office365.com (2603:10b6:806:2d0::27) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.35 via Frontend Transport; Wed, 8 Apr 2026 05:31:57 +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 SN1PEPF0002BA4F.mail.protection.outlook.com (10.167.242.72) 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, 8 Apr 2026 05:31:59 +0000 Received: from DLEE205.ent.ti.com (157.170.170.85) 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, 8 Apr 2026 00:31:56 -0500 Received: from DLEE203.ent.ti.com (157.170.170.78) by DLEE205.ent.ti.com (157.170.170.85) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 8 Apr 2026 00:31:56 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) by DLEE203.ent.ti.com (157.170.170.78) 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, 8 Apr 2026 00:31:56 -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 6385VtHK1351869; Wed, 8 Apr 2026 00:31:56 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Subject: [PATCH v4 3/4] Documentation: sound: Add TAS675x codec mixer controls documentation Date: Wed, 8 Apr 2026 00:31:47 -0500 Message-ID: <20260408053149.1369350-4-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260408053149.1369350-1-sen@ti.com> References: <20260408053149.1369350-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: SN1PEPF0002BA4F:EE_|IA1PR10MB7168:EE_ X-MS-Office365-Filtering-Correlation-Id: 929a30ea-d8b6-4fce-25d3-08de9530283d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|1800799024|36860700016|7416014|376014|18002099003|56012099003|22082099003; X-Microsoft-Antispam-Message-Info: 5MApn4++ylWtBlvH/tNIRBOzNIW11FQUo58WQWEoz6xqfzcM+Zqy75avDUsYLUoW0NTQABqEuiT3jNKKxqWiuQmeep2GV66ZTxhfoFcvS2jUEGd5shUMsldX2GJa864ISSDYpugI7gGZq5K8k7qTwCac5PLZfU9U5VsBgXCCXIeF9dZJ7qDFW5wdMefUOCo+8ndNyPj90fw69nnYTpgofifXGOSQTX8TV9r3Qp9pCdfS+Jfo1UYqeI3HUao7izVvF+bqwUz+iZBgLr4tWDS/mJHGSTVE9gu2kOcBIKuTJToHqtd9ZVWgPg5XtN0ujQExSA9ppuEX4O73dTGWXb5Q7PfixZKyktnd/S7efwuYMGwsBq1A3w5S6gSMepJGUQnfygyEKYZ3gnJMKKXImQS/J+S8dyJrzf7rfMHYyU8QbYOznM4QDFev5k/jzHOlrrTc7QKc+qh3x6u0aq/C73yn3HGQysBKqfYUfVUxXJnfftATvKJF9iCwazs0mrl6Mr9FW84GZqxvOAnAvJIiVYRN9zqF9sVoxvTm4pG6gKnVkg+H1Bj3OkWoM2kv7PCcRGc41hT8u4vSo56VFn/trTO9ixDzTvz+9LjmO/Eo2xgoGQu0qsRidwD4yWlwmv40t6x89mWnmr1VIFZ4CH0rd3FqzzREY5DaZMEbhTnv3AcL5UZneiGbvm2RTgMn6xMhAQVAjcoprkJhZ+ATSdnjMmD6hSZXMxNnLQlsad0f35tYVcMVXhTjuLAf2rXV4X0D4P8XkW5+NqRMIT9WaqfSVLRUyg== 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)(82310400026)(1800799024)(36860700016)(7416014)(376014)(18002099003)(56012099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: b6A7Kn6ypGqvHksH1iA2dwTY5RI43h47k5nPFqkv+nvnnnFJv3aVWiUmpSQsCGHH4S86Jp1TyEFtAPAQAPkJMh2PPqTOGHFAeNxbf9iuKnh4MtAmUdxxuNmFm4x6VwUmG3Q1+cdPVr5FMFMJioBU7sHuRTy77QXEbixaREdtgx1FwDp/jQYxUXFRKYaWL5MJJ+gDFj8eHP2qy5gwZ1BCAN/JnlBpO2MglI/RMXF3FHG7raXNnCNrmF2nZJRjBoaFkP2JqQ2ZvipANNHW3G7tXqclCO1pWTuTksuEQLqjpG3hx5zS97CyNF1A5jiTpjwiyZ4cMUudcfU6KcUt/zmAPY+2uDITacbPCuRD8IcdxJe1mnRLWYNFfP+urgk0pAaaE+tvCVXvsJcJjtzHjW2T1n9L8nTJmbbezimregSWT4TcK8qtFW9hvj52bTRvbxaS X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Apr 2026 05:31:59.8482 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 929a30ea-d8b6-4fce-25d3-08de9530283d 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: SN1PEPF0002BA4F.namprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: IA1PR10MB7168 Add ALSA mixer controls documentation for the TAS67524 driver, covering DSP signal path modes, volume controls, load diagnostics, and fault monitoring. Signed-off-by: Sen Wang --- Changes in v3: - Added register section - Added few addintional notes for clarification Changes in v2: - None Documentation/sound/codecs/index.rst | 1 + Documentation/sound/codecs/tas675x.rst | 686 +++++++++++++++++++++++++ 2 files changed, 687 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..3b99c31593cf --- /dev/null +++ b/Documentation/sound/codecs/tas675x.rst @@ -0,0 +1,686 @@ +.. 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 amplifier driver. + +For device tree bindings, see: +Documentation/devicetree/bindings/sound/ti,tas67524.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 +:Register: 0x32 bits [1:0] + +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) +:Register: 0x4A (CH1/CH2), 0x4B (CH3/CH4) + +Analog Gain Ramp Step +--------------------- + +:Description: Anti-pop ramp step duration for analog gain transitions. +:Type: Enumerated +:Default: 15us +:Options: 15us, 60us, 200us, 400us +:Register: 0x4E bits [3:2] + +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) +:Register: 0x40 (CH1), 0x41 (CH2), 0x42 (CH3), 0x43 (CH4) + +Volume Ramp Down Rate +--------------------- + +:Description: Update frequency during mute transition. +:Type: Enumerated +:Default: 16 FS +:Options: 4 FS, 16 FS, 32 FS, Instant +:Register: 0x44 bits [7:6] + +Volume Ramp Down Step +--------------------- + +:Description: dB change per update during mute. +:Type: Enumerated +:Default: 0.5dB +:Options: 4dB, 2dB, 1dB, 0.5dB +:Register: 0x44 bits [5:4] + +Volume Ramp Up Rate +------------------- + +:Description: Update frequency during unmute transition. +:Type: Enumerated +:Default: 16 FS +:Options: 4 FS, 16 FS, 32 FS, Instant +:Register: 0x44 bits [3:2] + +Volume Ramp Up Step +------------------- + +:Description: dB change per update during unmute. +:Type: Enumerated +:Default: 0.5dB +:Options: 4dB, 2dB, 1dB, 0.5dB +:Register: 0x44 bits [1:0] + +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 +:Register: 0x46 bits [1:0] + +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 +:Register: 0x46 bits [3:2] + +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) +:Register: 0x47 bit [0] (CH1), bit [1] (CH2), bit [2] (CH3), bit [3] (C= H4) + +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. +:Register: 0x47 bit [4] + +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 +:Register: 0x48 bits [7:4] (CH1), bits [3:0] (CH2), + 0x49 bits [7:4] (CH3), bits [3:0] (CH4) +: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 +:Register: 0x61 bits [1:0] + +SS Triangle Range +----------------- + +:Description: Frequency deviation range for Triangle spread spectrum. +:Type: Enumerated +:Default: 6.5% +:Options: 6.5%, 13.5%, 5%, 10% +:Register: 0x62 bits [1:0] +: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% +:Register: 0x62 bits [6:4] +: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 +:Register: 0x62 bits [3:2] +:Note: Applies only when Spread Spectrum Mode includes Random. + +SS Triangle Dwell Min +--------------------- + +:Description: Minimum dwell time at Triangle spread spectrum frequency ext= remes. +:Type: Integer +:Default: 0 +:Range: 0 to 15 (0 =3D feature disabled) +:Register: 0x66 bits [7:4] +:Note: Counts in FSS clock cycles. The modulator holds the extreme + frequency for at least this many FSS cycles before reversing. + When Dwell Min equals Dwell Max, the dwell feature is inacti= ve. + For FSS values at each PWM frequency refer to the "Spread + Spectrum" section of the TRM. + +SS Triangle Dwell Max +--------------------- + +:Description: Maximum dwell time at Triangle spread spectrum frequency ext= remes. +:Type: Integer +:Default: 0 +:Range: 0 to 15 (0 =3D feature disabled) +:Register: 0x66 bits [3:0] +:Note: Counts in FSS clock cycles. Must be >=3D Dwell Min. When Dwe= ll Max + equals Dwell Min, the dwell feature is inactive. + +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) +:Register: 0x8F bit [1] +: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 +:Options: Level 4, Level 3, Level 2, Level 1 +:Register: 0x55 bits [1:0] +:Note: Level 4 is the least sensitive (highest trip current); Level= 1 is + the most sensitive. The exact ILIM values depend on operating + conditions (PVDD voltage, switching frequency, and temperatu= re). + Refer to the Electrical Characteristics table and the + "Overcurrent Limit (Cycle-By-Cycle)" section of the TRM. + +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 +:Register: 0xE2 bits [6:4] (CH1), bits [2:0] (CH2), + 0xE3 bits [6:4] (CH3), bits [2:0] (CH4) + +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 +:Register: 0x74 + +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 +:Register: 0x75 + +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 +:Register: 0xBB bits [7:6] (CH1), bits [5:4] (CH2), + 0xBC bits [3:2] (CH3), bits [1:0] (CH4) + +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 initialization 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. + +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) +:Register: 0xB0 bit [0] +:Note: Active-low, when enabled, affected channels re-run diagnosti= cs after + fault recovery and retry approximately every 750 ms until re= solved. + +CHx LO LDG Switch +~~~~~~~~~~~~~~~~~ + +:Description: Enables line output load detection per channel (x =3D 1, 2, = 3, 4). +:Type: Boolean Switch +:Default: Disabled (0) +:Register: 0xB1 bit [3] (CH1), bit [2] (CH2), bit [1] (CH3), bit [0] (C= H4) +: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 +:Register: 0xB2 bits [7:6] + +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 +:Register: 0xB2 bits [5:4] + +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 +:Register: 0xB2 bits [3:2] + +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 +:Register: 0xB2 bits [1:0] + +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 +:Register: 0xB3 bits [7:4] (CH1), bits [3:0] (CH2), + 0xB4 bits [7:4] (CH3), bits [3:0] (CH4) + +DC LDG Result +~~~~~~~~~~~~~ + +:Description: Overall DC diagnostic result register. +:Type: Integer (read-only) +:Range: 0x00 to 0xFF +:Register: 0xC2 +: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 +:Register: 0xC0 bits [7:4] (CH1), bits [3:0] (CH2), + 0xC1 bits [7:4] (CH3), bits [3:0] (CH4) +: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 +:Register: 0xC2 bit [7] (CH1), bit [6] (CH2), bit [5] (CH3), bit [4] (C= H4) + +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 +:Register: 0xD9 bits [7:6]/[5:4]/[3:2]/[1:0] (MSB for CH1=E2=80=93CH4), + 0xDA (CH1 LSB), 0xDB (CH2 LSB), 0xDC (CH3 LSB), 0xDD (CH4 LS= B) + +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 LDG 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) +:Register: 0xB5 bit [4] +: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 +:Register: 0xB8 + +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) +:Register: 0xC3 (CH1 Real), 0xC4 (CH1 Imag), 0xC5 (CH2 Real), 0xC6 (CH2= Imag), + 0xC7 (CH3 Real), 0xC8 (CH3 Imag), 0xC9 (CH4 Real), 0xCA (CH4= Imag) +:Note: Scale set by AC LDG Gain. + +Speaker Protection & Detection +------------------------------- + +Tweeter Detection Switch +~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Enables tweeter detection using the AC impedance magnitude c= omparator. +:Type: Boolean Switch +:Default: Enabled (1) +:Register: 0xB6 bit [0] +:Note: The underlying register bit is TWEETER DETECT DISABLE (activ= e-low). + Control value 1 =3D detection enabled (register bit 0), 0 = =3D disabled + (register bit 1). + +Tweeter Detect Threshold +~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: Magnitude threshold for tweeter detection. +:Type: Integer +:Default: 0 +:Range: 0x00 to 0xFF +:Resolution: 0.8 ohm/code (AC LDG Gain=3D0) or 0.1 ohm/code (AC LDG Gain= =3D1) +:Register: 0xB7 + +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 +:Register: 0xCB bit [3] (CH1), bit [2] (CH2), bit [1] (CH3), bit [0] (C= H4) + +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) +:Register: 0x3A bit [0] + +PVDD Foldback Switch +-------------------- + +:Description: Enables automatic gain limiting when supply voltage drops + (Automatic Gain Limiter). +:Type: Boolean Switch +:Default: Disabled (0) +:Register: 0x3A bit [4] + +DC Blocker Bypass Switch +------------------------ + +:Description: Bypasses the DC-blocking high-pass filter. +:Type: Boolean Switch +:Default: Not bypassed (0) +:Register: 0x39 bit [0] + +Clip Detect Switch +------------------ + +:Description: Enables DSP-based clip detection (Pseudo-Analog Clip Detect). +:Type: Boolean Switch +:Default: Disabled (0) +:Register: 0x93 bit [6] + +Audio SDOUT Switch +------------------ + +:Description: Routes post-processed audio to the SDOUT pin instead of + Vpredict data. +:Type: Boolean Switch +:Default: Disabled (0) +:Register: 0x3A bit [5] +:Note: When enabled, replaces Vpredict data on SDOUT with post-proc= essed + SDIN. All SDOUT configurations that apply to Vpredict also a= pply + to SDIN-to-SDOUT transmission. + +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) +:Register: 0x37 bit [3] (CH1), bit [2] (CH2), bit [1] (CH3), bit [0] (C= H4) + +RTLDG Clip Mask Switch +---------------------- + +:Description: Suppresses impedance updates during clipping events. +:Type: Boolean Switch +:Default: Enabled (1) +:Register: 0x37 bit [4] + +ISENSE Calibration Switch +-------------------------- + +:Description: Enables current sense calibration for accurate impedance + measurements. +:Type: Boolean Switch +:Default: Disabled (0) +:Register: 0x5B bit [3] + +RTLDG Open Load Threshold +-------------------------- + +:Description: DSP coefficient for open load fault detection threshold. +:Type: DSP coefficient (extended control) +:Register: DSP Book 0x8C, page 0x22, 0x98 + +RTLDG Short Load Threshold +--------------------------- + +:Description: DSP coefficient for shorted load fault detection threshold. +:Type: DSP coefficient (extended control) +:Register: DSP Book 0x8C, page 0x22, 0x9C + +CHx RTLDG Impedance +------------------- + +:Description: Real-time load impedance per channel (x =3D 1, 2, 3, 4). +:Type: Float (read-only, displayed in ohms) +:Register: 0xD1=E2=80=930xD2 (CH1), 0xD3=E2=80=930xD4 (CH2), 0xD5=E2=80= =930xD6 (CH3), 0xD7=E2=80=930xD8 (CH4) +: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 +:Register: 0x8B +:Note: See bit encoding table at the start of this section. + Reading the register clears all latched bits. + +Driver Known Limitations +=3D=3D=3D=3D=3D=3D=3D=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,tas6752= 4.yaml +- ALSA Control Name Conventions: Documentation/sound/designs/control-names= .rst --=20 2.43.0 From nobody Tue Jun 16 11:15:46 2026 Received: from CH5PR02CU005.outbound.protection.outlook.com (mail-northcentralusazon11012022.outbound.protection.outlook.com [40.107.200.22]) (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 61B5F35AC2B; Wed, 8 Apr 2026 05:32:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.200.22 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626322; cv=fail; b=bsssY87jK5ZzNAjohIJ33bXixYbaWDn8BGcl4JwgDDZLI2DxbL/zu0EW6KYxEvDQ7nLGknXiR0sBYa14hAEaFNBt+ImkR9NfnPdOHol9X1Mq5uGPGN1VXrW44DxVErFd2vG2ScypGAbAz2F6qhTxJAxmrV5XVS0P3Gzz+FSyadw= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775626322; c=relaxed/simple; bh=SVN8RK6t5iCrczHTqjkg0f73rjkmsVj4yCPx2wZLCDA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=UncWRVsy7WLWJy6pHXy+gTRbwm8841Tvbu/4O9XJ48bIpDQHUR4ByVxpnykhlEVID9/ypQZZXliA+tKYzMdlvLxq/4IMvvI2cjg18ckTFS2e8Gn61YZ/4ZmyNdrKEh+tALijhwoTBAk83pR2FC/pt1XB1bh7EZsFMkAijx7TMm4= 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=CzQgX19w; arc=fail smtp.client-ip=40.107.200.22 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="CzQgX19w" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=DsfBsjeNQM6yo1HNaza2BBNEGrvHswywQ+PHgtCclAKqMwTsukA6oyB1vGygKB8Qbat8moApcEIrBAWlWHjYB0HxBr4MtRmjDzuiRRi2k+n1imIJqWiE9HZ5uMxcDnm56mcQJAellJYjtoDE9M+K6fGVOhneJ6uY/Tp2ho50x0sakNGcn2xFZ0448EbyPmok0ORojzCpnw1p6Gv3qnTgj4h+FS0DVyy/FM4q1oz1grVJTfXdANUfAjFD9/tG+Wa3Zr7UizHqNgag1nOpj2rMAvDb8u0DdBsjiHuozxNTcr1wtvTj1De1EYVGeIWZuodKfCRJrVpFJfeNsUENbHjEsg== 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=fILuxeyIumz5Vd6OzcJl2nKcEwZuotrnTRDBBoqNeNo=; b=yYX2iCfmQCm0zqGkrQQ7pYl/My2sgDgkpvgWWy/URE6IQtcmLjF1bR40H96Chh4Zn8eDYMIVuXwCdLch/VTGmgIchzmRvdKyR8f1V+6h46dl3c7vd1xIq7HfGZrQ7pC1MZtSJ1on1h44UuPINQVPql1/YeaWJD5UDraJFzrktJf7DdTeceopLWCw1H9NPDbp55WWNV3kpj6Kcm+sVUoVOakCOYG2+fYLiRC3T1AtWX7v8qSXFcMjXPDRqBzNYF2qsXPo3IgDKprx2ADcLBVlJz0JBB+7kHTNzSgwP7KYpCMFY197bLbeNqluMidlDaCdrN0JLtEAwtz1xUC7eUFocg== 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=fILuxeyIumz5Vd6OzcJl2nKcEwZuotrnTRDBBoqNeNo=; b=CzQgX19wmIJF+YVPxR23fxkM3WiYvCw5jJAmSNUXUb+dU8gfH+gx2rDdI23On9rMYWaKohFezqcnlKAfNz8178Jrsu3tHb3HI9ybKbgbrTotRjzqAihjzZzBZhwr8ykCEEQ5DtQ9T5pQVCBkgomLQrS5JAkuMSWBsrX3z8/Dhjc= Received: from SN6PR04CA0101.namprd04.prod.outlook.com (2603:10b6:805:f2::42) by PH8PR10MB6503.namprd10.prod.outlook.com (2603:10b6:510:229::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9769.17; Wed, 8 Apr 2026 05:31:58 +0000 Received: from SN1PEPF0002636D.namprd02.prod.outlook.com (2603:10b6:805:f2:cafe::8b) by SN6PR04CA0101.outlook.office365.com (2603:10b6:805:f2::42) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9769.33 via Frontend Transport; Wed, 8 Apr 2026 05:31:58 +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 SN1PEPF0002636D.mail.protection.outlook.com (10.167.241.138) 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, 8 Apr 2026 05:31:57 +0000 Received: from DFLE205.ent.ti.com (10.64.6.63) 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, 8 Apr 2026 00:31:57 -0500 Received: from DFLE202.ent.ti.com (10.64.6.60) by DFLE205.ent.ti.com (10.64.6.63) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Wed, 8 Apr 2026 00:31:56 -0500 Received: from lelvem-mr05.itg.ti.com (10.180.75.9) by DFLE202.ent.ti.com (10.64.6.60) 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, 8 Apr 2026 00:31:56 -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 6385VuOL162470; Wed, 8 Apr 2026 00:31:56 -0500 From: Sen Wang To: CC: , , , , , , , , , , , , , , , , Subject: [PATCH v4 4/4] MAINTAINERS: add entry for TAS67524 audio amplifier Date: Wed, 8 Apr 2026 00:31:48 -0500 Message-ID: <20260408053149.1369350-5-sen@ti.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260408053149.1369350-1-sen@ti.com> References: <20260408053149.1369350-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: SN1PEPF0002636D:EE_|PH8PR10MB6503:EE_ X-MS-Office365-Filtering-Correlation-Id: 6e6447e0-c50a-4ea9-2a67-08de953026d8 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|1800799024|82310400026|36860700016|376014|7416014|56012099003|22082099003|18002099003; X-Microsoft-Antispam-Message-Info: QHMTPdOqUmhE8SLVoGqZgbGLfoeJwB2Meur8tadZNOLGzgII1Xkd8YLSI9JKHhEAoRwOpX16iufv8AXmB4sHSK2kgclnHelLh1MWVLanM1k7MyNgE048qxRIyAV1TAiqkk2fPK/EzJzE0tQhvJ4eBAktJZ7i/+PilbbIJS6JTAhUIqvKJ7O9dpl4Gmf8K0UdYvN6vp85AskLFju8yxU9HTCjEKnbfxBww+Tloir0XmFWHtKKD6SL1dYEq77P8RJg1HC4IguXRUYuRe3ymZOZSFN9ywL8EqRIu2IpiDU9o+TqwhleVIMWJs0lT5QR9PkjkCOsAf3kH14E6n49bA3sgf8vZcr6FV6AAbwr0VSKEgoNTXkGPRk9tybq+ds7oUiWIjWoqegq0SVEQkAf37VbNk++DTu3FvNXQQzME0JKoa6QqcT1DNavR6Jo4yip81vXRViqZAoqLj2zUw89r04EMNCfvpxyJFQRJAl/QQJgheaqQufkn7NqBwAKMQM3AKIDeanA8I9e1ll/Td0EdcqAVwrIsi052vMso9l2B+pzy0lu5rp1T0yZEwGyr/9NMaWgGQSnG6SllTZV21yGJBAZtlVoWnuFU/lQnTtVeKfFvnkA0+KSLYg/EbPBFbhFcN3reAUgjwqIFqX2lJB2aPnFPrH5SiEv+LTgaeRg+1BBVKCIxM3ZOWVPog9O/mKI8E2qJI8/beye/vxay578j66SUyETkEpUIydf/xvk6YhS4vgSpsa5qwvuopiijGuVLWJjtqE8dKu8aFuOtB1sXm+IZA== 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)(1800799024)(82310400026)(36860700016)(376014)(7416014)(56012099003)(22082099003)(18002099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: j/sdPxFJwCPAqXej8VJYehFR00KAAbv/7gU+T99AEGGUoNnAn3wHkhFThNzSm1GpW4cJZEEgauloR6q2KiMVfwAEDhIHvrwpE0VI0BzlLjcotuu81AGKjRSii10ubZJkO0Lgk0azIlvKJ/B5/zU1T08Ipb+DTTp2Sbq7xrk1e5mSnUvVP7W8eOlc2gl4ymGQowV95XtmpkBNMH4Bkiy9yZj+uvCV2VLPJdDo/ZQAf8KgR9r/T+I2zLngb9NRjU0eTYx1/bu0Sfwp+GQOryQIHw9fWCk0OM/nLwthi7niAQaX+i6slSLBfWEUl2Fj1LYmLDDNtekCPb8J3A7nmPTXmIvaFncbZMuI/ReQPyca5w40ATyUtD4FLHPKKgtGzqpWqAuq9EMF2Ci+HjzPebB64uRT/TDV+os2u55CeFe+6y3qvZ4QgWuYpmqhwIKx5puq X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Apr 2026 05:31:57.5208 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 6e6447e0-c50a-4ea9-2a67-08de953026d8 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: SN1PEPF0002636D.namprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: PH8PR10MB6503 Content-Type: text/plain; charset="utf-8" Add Sen Wang as maintainer and register file patterns for the newly added TAS67524 amplifier driver. Signed-off-by: Sen Wang --- MAINTAINERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a626dee5c106..a78b6cb9b907 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,tas67524.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/tas675x* 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/tas675x*.* F: sound/soc/codecs/tlv320*.* F: sound/soc/codecs/tpa6130a2.* =20 --=20 2.43.0