From nobody Tue Jun 16 17:01:46 2026 Received: from BYAPR05CU005.outbound.protection.outlook.com (mail-westusazon11010067.outbound.protection.outlook.com [52.101.85.67]) (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 30F8B40DFCF; Thu, 30 Apr 2026 14:46:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.85.67 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777560387; cv=fail; b=BRW1dvwTLfrmIME2Jz7SvMJ4lT+gFQtAj2/LX4BWpg6XqajHga9u4e/1IDymiqKhAoxFlHmcrRx4OwyKt7x1SYaBF7/t3ADP/MQRCpCmUq/OGa2y/C0PllG7zv27bswqbp7bHtUd5h9YYpsrGC1cjqEwzuKIfgY7yEjdPXyro28= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777560387; c=relaxed/simple; bh=7ATEQWhLA882gs1UT1gYMxBAo70SJriAhKSI76w0uUo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=d27QPYbuHlYvRkHMbbDi/1k1sol0mArKQZOobBrd4XvJqgGPC74tVNge5ta229pnhYwwcIZWxP+1wUDfgT4cCj9ugGYtYwmpyklArq/rWUfTIR2bfLZHupLmqrpc7rnY3IBDeH6Uc+l08xmClrhQPASWhRSh/iH2KefZFnP61KY= 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=NHLi+HfE; arc=fail smtp.client-ip=52.101.85.67 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="NHLi+HfE" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=EwI1/sBubEszgizrIglcpc2kgUyxfsehHH8/gxtsIsrO4KDOYovs279haY/W0YAn1zPZxLTCh6qX1d1d7SaAANJztNFhnqFcsmJ4NhwZrh03THUtrEqF1JfQSAzTruHeoHTtEJO1PeADIQX8mqUwAmbAntRzgHV+Ya3LlGN+I+orj3hyqP4b7C3o+Yo9/KTMSWnT+i2V0/7JTIiPktNgMc0vxcvqoqrS9o8DPdTNgL6x8VG9uECSyhO5v8om2SqZfYIqnDhgrfIYoAOXVLlhyW2UEJtFfH9aWOcm5JWSa63qHUvt82V9BW1qOtcc+9XpN/0D2VmUZp33bUdMP3OTOA== 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=g7vVuX6xM5DYT5fVNeqeH2ClsKqUAUNI4n2kSLrRWzQ=; b=uL+WIKRzchphuZWWortBWGpU9RsMBRr0K974m6owZIBDRr7aXHX+ODArhaW4G/lrMFV8ub5S9hXfkSKsGYw0xICgnil+/zaoVpqKK8DQy6Nga5JR5aTMko0I5eW1zSsB3kzWlJbdwLhMci7z4rSl5/GYHFCl+yfSFt/MHI9H76fbi0VpYgA/2KIf6Fx4pCXU8qP0iiWkEjyRqM60N/tJK5MgTFJ8clOFfI5thvedl15IVz8szxt3BYhGCBpyi4KqE8zb7NJsKF22A99XOsmn2xfaCYAFSCBpAj3s6RxWP4MMDJ0G+BHFmwEqHgAIBUQP/bvckomylvXuZCVnKHUNVQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.23.194) smtp.rcpttodomain=linux.dev 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=g7vVuX6xM5DYT5fVNeqeH2ClsKqUAUNI4n2kSLrRWzQ=; b=NHLi+HfE1lLBqbgO2URCiO4s9YkeELHOl4R8yE+88gECkUzHt6pW4LtBMevF0T7l97TzuFLbR7rgv+ttkObAHLtc5ywIq8+4CTdVpfn6XFBKt9WLdJwx4xLg00ELK6E0BNuK0MSfatvqCnqeGaptFZHBuFp+GVccDLqerZEgVTw= Received: from BN9PR03CA0158.namprd03.prod.outlook.com (2603:10b6:408:f4::13) by MW4PR10MB5704.namprd10.prod.outlook.com (2603:10b6:303:18e::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9870.22; Thu, 30 Apr 2026 14:46:23 +0000 Received: from MN1PEPF0000F0E4.namprd04.prod.outlook.com (2603:10b6:408:f4:cafe::8c) by BN9PR03CA0158.outlook.office365.com (2603:10b6:408:f4::13) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9846.30 via Frontend Transport; Thu, 30 Apr 2026 14:46:23 +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 MN1PEPF0000F0E4.mail.protection.outlook.com (10.167.242.42) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.18 via Frontend Transport; Thu, 30 Apr 2026 14:46:22 +0000 Received: from DLEE202.ent.ti.com (157.170.170.77) 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; Thu, 30 Apr 2026 09:46:20 -0500 Received: from DLEE201.ent.ti.com (157.170.170.76) by DLEE202.ent.ti.com (157.170.170.77) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Thu, 30 Apr 2026 09:46:19 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) by DLEE201.ent.ti.com (157.170.170.76) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Thu, 30 Apr 2026 09:46:19 -0500 Received: from LTPW0EX92E.dhcp.ti.com (ltpw0ex92e.dhcp.ti.com [10.82.30.14]) by lelvem-mr06.itg.ti.com (8.18.1/8.18.1) with ESMTP id 63UEk6Mi1332278; Thu, 30 Apr 2026 09:46:14 -0500 From: Niranjan H Y To: CC: , , , , , , , , , , , , , , , , Niranjan H Y Subject: [PATCH v14 1/4] ASoC: SDCA: Add PDE verification reusable helper Date: Thu, 30 Apr 2026 20:15:51 +0530 Message-ID: <20260430144554.1335-2-niranjan.hy@ti.com> X-Mailer: git-send-email 2.33.0.windows.2 In-Reply-To: <20260430144554.1335-1-niranjan.hy@ti.com> References: <20260430144554.1335-1-niranjan.hy@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: MN1PEPF0000F0E4:EE_|MW4PR10MB5704:EE_ X-MS-Office365-Filtering-Correlation-Id: d466f23c-e241-478e-0dd2-08dea6c73fc3 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|82310400026|7416014|376014|1800799024|36860700016|18002099003|22082099003|56012099003; X-Microsoft-Antispam-Message-Info: kmLSm8nvk0Frcv3cQby1nQ0JRasagrESC4+Uc51Z+/Ch3el6dW9fgfVH5TT3BKPdf8aOh5Onn1K4MpxPWvCBaezu8RtaD3gwIr6nBQ3wsfxuwNYKPnE/V/ppJ3o+P1dHYlsFIM/5mniwinuSuFCMewPx8ULRNh/8y3HjoZq61J/UI+bdxECwQ9GQOiMZrYyq7U0YfeHTL+gXmEIWC1ljPKJ7cjPI6xkamBSteDFNkFp5cBri43Vqh9w/FUfAIdb+wF70/6AbHjOMDbQSa6P8ePZmkTL88JrEzeX4LdP8+rvKAruM+uooIvIkEBO6Qi//tVonCmZh7puXmwC7q0uAJ6LHV6141+2eW9GVcSUuxK0mYNzz7pChafm5+Dr1kgc3+5nd5lKAS9GdvEjJEYaiMMcEzPNJms7SfBldc6zzmOc8GP1ZieXzEhx0/es0o6FUVA5C1H1trv5+ZGsVl6o405XYMUbEypuQ5+Me2yu9WdC0SF7YGmmf7cvq51pvLQRiCUxlX4BcicJh8w8SqHKadhZf07IgAB0qlrhTTQQhaIwYmad8syWA5A6Tdv2nxsG+W38A1lltPTYUAGuRqIw0G/hyJgg6Xzir4plzBoZxHjfdeZXP+kPRPnQMY2Tbf9cpArw0gjy2hpvJwuv7pxyTdc/QorCAXwLpD1mAM15HQyhotiD48fo/pzx/yU0/CVXJNpzJnAnxfi5jkQmosV7UXItGB/cC/kmVbrYJB7RPyfqMZl4oHubpIT/TQpBPCF8wee3P5JNAZfemdHwViUaErQ== X-Forefront-Antispam-Report: CIP:198.47.23.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:lewvzet200.ext.ti.com;PTR:InfoDomainNonexistent;CAT:NONE;SFS:(13230040)(82310400026)(7416014)(376014)(1800799024)(36860700016)(18002099003)(22082099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: LM2x+zdO6/4vLh6RRrTZcpbAKkK2di7spsZ6/bdDyooUW7+L/BloIZA37aLLxquKEzBsSmj6x77igbbhFMvaGUtNqpVVW4u7/vCgxy4qVkw407cUpwjSdFB7gunCPLh/7OFtvhqhYnRbV8B0vkwC5nYxMaVr6ZJvNO7I/p5AWxc2L4TX2uUPNFlm+Z68Y6r6FwAgyqtvsqAKsmX5Z6FwHBYvS96scNKjDmDOdklh7ZbBo1/fDP3GQvwBmfLAc1+MNK8szUcMCZ6babBozfomfIs8SKTc0m1O+kCittrpXIoUhf3blc2xqunCOy4L8foz9Yxlkl9LjBbCnRozwYIRyuU0Lq6poyu+lFlkTrKHhhEGgo9taay0mRHxsxSoIi18DKVWSfrlxuHtWkWJwQdP7vGjotRyL0R1AtGLjzSUTMJvJ+GLtcS54vSoDILXAiLM X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Apr 2026 14:46:22.9065 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d466f23c-e241-478e-0dd2-08dea6c73fc3 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: MN1PEPF0000F0E4.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: MW4PR10MB5704 Content-Type: text/plain; charset="utf-8" Implement sdca_asoc_pde_ensure_ps() helper function to poll for PDE power state transitions. Per SDCA specification, after writing REQUESTED_PS, drivers must poll ACTUAL_PS until the target power state is reached. Changes include: - Add sdca_asoc_pde_ensure_ps() to handle ACTUAL_PS polling with support for device-specific delay tables or default intervals - Export function via sdca_asoc.h for use by SDCA-compliant drivers - Refactor entity_pde_event() in sdca_asoc.c to use the helper Signed-off-by: Niranjan H Y Reviewed-by: Charles Keepax --- v14: - Resending complete series (v13 1/4 was accidentally sent alone) - No code changes from v13 v13: - no change v12: - use correct namespace while exporting the variable - fix missing entity information while logging v11: - revert v10 changes - API is renamed from sdca_asoc_pde_ensure_ps to sdca_asoc_pde_poll_actual_ps v10: - write REQUESTED_PS before checking the target state. - change the API name sdca_asoc_pde_ensure_ps to sdca_asoc_set_pde_poll_sync v9: - newly added interface --- include/sound/sdca_asoc.h | 6 +++ sound/soc/sdca/sdca_asoc.c | 106 ++++++++++++++++++++++++++----------- 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/include/sound/sdca_asoc.h b/include/sound/sdca_asoc.h index 46a61a52d..ca35d5a44 100644 --- a/include/sound/sdca_asoc.h +++ b/include/sound/sdca_asoc.h @@ -13,6 +13,7 @@ struct device; struct regmap; struct sdca_function_data; +struct sdca_pde_delay; struct snd_ctl_elem_value; struct snd_kcontrol; struct snd_kcontrol_new; @@ -99,4 +100,9 @@ int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontro= l, struct snd_ctl_elem_value *ucontrol); int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap, + int function_id, int entity_id, + int from_ps, int to_ps, + const struct sdca_pde_delay *pde_delays, + int num_delays); #endif // __SDCA_ASOC_H__ diff --git a/sound/soc/sdca/sdca_asoc.c b/sound/soc/sdca/sdca_asoc.c index 2bfc8e5ae..e76afa396 100644 --- a/sound/soc/sdca/sdca_asoc.c +++ b/sound/soc/sdca/sdca_asoc.c @@ -359,15 +359,77 @@ static int entity_parse_ot(struct device *dev, return 0; } =20 +/** + * sdca_asoc_pde_poll_actual_ps - Verify PDE power state reached target st= ate + * @dev: Pointer to the device for error logging. + * @regmap: Register map for reading ACTUAL_PS register. + * @function_id: SDCA function identifier. + * @entity_id: SDCA entity identifier for the power domain. + * @from_ps: Source power state (SDCA_PDE_PSn value). + * @to_ps: Target power state (SDCA_PDE_PSn value). + * @pde_delays: Pointer to array of PDE delay specifications for this devi= ce, + * or NULL to use default polling interval. + * @num_delays: Number of entries in pde_delays array. + * + * This function polls the ACTUAL_PS register to verify that a PDE power s= tate + * transition has completed. Per SDCA specification, after writing REQUEST= ED_PS, + * the caller must poll ACTUAL_PS until it reflects the requested state. + * + * This function implements the polling logic but does NOT modify the powe= r state. + * The caller is responsible for writing REQUESTED_PS before invoking this= function. + * + * If a delay table is provided, appropriate polling intervals are extract= ed based + * on the from_ps and to_ps transition. If no table is provided or no matc= hing entry + * is found, a default polling interval is used. + * + * Return: Returns zero when ACTUAL_PS reaches the target state, -ETIMEDOU= T if the + * polling times out before reaching the target state, or a negative error= code if + * a register read fails. + */ +int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap, + int function_id, int entity_id, + int from_ps, int to_ps, + const struct sdca_pde_delay *pde_delays, + int num_delays) +{ + static const int polls =3D 100; + static const int default_poll_us =3D 1000; + unsigned int reg, val; + int i, poll_us =3D default_poll_us; + int ret; + + if (pde_delays && num_delays > 0) { + for (i =3D 0; i < num_delays; i++) { + if (pde_delays[i].from_ps =3D=3D from_ps && pde_delays[i].to_ps =3D=3D = to_ps) { + poll_us =3D pde_delays[i].us / polls; + break; + } + } + } + + reg =3D SDW_SDCA_CTL(function_id, entity_id, SDCA_CTL_PDE_ACTUAL_PS, 0); + + for (i =3D 0; i < polls; i++) { + if (i) + fsleep(poll_us); + + ret =3D regmap_read(regmap, reg, &val); + if (ret) + return ret; + else if (val =3D=3D to_ps) + return 0; + } + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_NS(sdca_asoc_pde_poll_actual_ps, "SND_SOC_SDCA"); + static int entity_pde_event(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kctl, int event) { struct snd_soc_component *component =3D snd_soc_dapm_to_component(widget-= >dapm); struct sdca_entity *entity =3D widget->priv; - static const int polls =3D 100; - unsigned int reg, val; - int from, to, i; - int poll_us; + int from, to; int ret; =20 if (!component) @@ -386,33 +448,17 @@ static int entity_pde_event(struct snd_soc_dapm_widge= t *widget, return 0; } =20 - for (i =3D 0; i < entity->pde.num_max_delay; i++) { - struct sdca_pde_delay *delay =3D &entity->pde.max_delay[i]; - - if (delay->from_ps =3D=3D from && delay->to_ps =3D=3D to) { - poll_us =3D delay->us / polls; - break; - } - } - - reg =3D SDW_SDCA_CTL(SDW_SDCA_CTL_FUNC(widget->reg), - SDW_SDCA_CTL_ENT(widget->reg), - SDCA_CTL_PDE_ACTUAL_PS, 0); - - for (i =3D 0; i < polls; i++) { - if (i) - fsleep(poll_us); - - ret =3D regmap_read(component->regmap, reg, &val); - if (ret) - return ret; - else if (val =3D=3D to) - return 0; - } + ret =3D sdca_asoc_pde_poll_actual_ps(component->dev, component->regmap, + SDW_SDCA_CTL_FUNC(widget->reg), + SDW_SDCA_CTL_ENT(widget->reg), + from, to, + entity->pde.max_delay, + entity->pde.num_max_delay); + if (ret) + dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=3D%d\n", + entity->label, from, to, ret); =20 - dev_err(component->dev, "%s: power transition failed: %x\n", - entity->label, val); - return -ETIMEDOUT; + return ret; } =20 static int entity_parse_pde(struct device *dev, --=20 2.34.1 From nobody Tue Jun 16 17:01:46 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012014.outbound.protection.outlook.com [52.101.48.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 550A12641CA; Thu, 30 Apr 2026 14:46:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.14 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777560401; cv=fail; b=H/We0Zlw4DmAkdnOugckGHs7X7hRebU0IMtURC68YBg4TySY6BRlVtUkG+iUaK+vPgJEljvXlanjqF4tJs2D4wY/RGmI1RARb10X1RGIBjpws/SJfXpcob9NwXdQ/fzKYWHK0J7Fypj1zUinO4NDiMO4ZQRzVpaVL3P0UMY1hGo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777560401; c=relaxed/simple; bh=IYYBqmtXtuEqxoyVFyUWeGIrAEx/ActEFgK+wLK7oZw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=uKOKyzmwdVM2szE1WYB6B8bJlPXaCCHogJaNSYu/m6ke+wMiPKWmwxHG7dDvGPVbhxr1bi4n8D8p/9Olhh2wuGurpNDbYpBo5UqE+3OzsXWliDV269y/dBTKlfbcfKKolefz5J1zJOD3nJRI+qfjzSSRU80RtVTCUEVfO7ZNChk= 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=wiJIr2M2; arc=fail smtp.client-ip=52.101.48.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="wiJIr2M2" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=LEe02FnavbLNKEJjJoXefgbrnMmQty14vJVS67wnvqasCQZ7L6fDM1cR4g2+U/hriIynzjkpkzYZT+zs3gQiUMcmAAvCKnYnCcQj6AbSYzdEzGZ1kWwi9r1v29tZ+tsYdfRbRAa75NWqy0PciTxGanE5dHi0uy/bBhlIYs1TD948WU3GyMA8TDh/j2YI/PmnDcsItMS/jILFjJUeMjWJ2Xt58HgFtsq/5R3Ikiysc+JTFFY5xhaYiRT6gxoa//EHiyIjiInE+wi3nnuZt3BUNHxL/rVHEHsp/NxnPSck2TKgu5En0dsblqNAQCMr6tH2m9PWcY+4sgyiQy4bBV9Znw== 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=50ofwJcR49bA0S9h23haEy/xMMfBojpQK17EdK5t/Ac=; b=AkHcm3uQKipBjo/nNN6/B6K/nlyYRhJKsF4n1suN7rLwiU3E0RQgepBekcBX8S520LW/JizCsFVXzEFx2qrakgjFmh4fA7bFx3/SwN+P/mM75YhQ27YHte2CbB4x6UaUcNwDluxeGeJQs+1jkwPvjvkDANXl4t1ni+ZVz508Tb9RCg1DcNQRkO1pctw3VFzmBD+RJK8A0oFmFFpTKdb5YAFCQf3tMNqvgEFbxqZ2VMbfu0ZXOCnE70DGW+XTyztUrK35cOMPXhlaql22uJxSwTYYQLP8xUx0LwpNZC+xmM3WXmrDQoHUp/3fwVppyE4Ii28JgF/ofwB3Uey6kaFrHg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.21.194) smtp.rcpttodomain=linux.dev 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=50ofwJcR49bA0S9h23haEy/xMMfBojpQK17EdK5t/Ac=; b=wiJIr2M2FNNW2sxFH8rA05/5ZFJnf6Ah4E19AlhGM6d+P/whRHDdGhHirphgnw/4UHyTEWhEHr36LP3jgVlgMlh80wyAvOQzi8cGq3ozoa0aNZjmNnkgoo6HH6EpYX2F85AMPvsP4J9IooQKJMEwjyIjS2TPgAzYa2gbMBrATQc= Received: from BYAPR07CA0054.namprd07.prod.outlook.com (2603:10b6:a03:60::31) by SA1PR10MB7553.namprd10.prod.outlook.com (2603:10b6:806:376::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9870.20; Thu, 30 Apr 2026 14:46:33 +0000 Received: from SJ1PEPF00002323.namprd03.prod.outlook.com (2603:10b6:a03:60:cafe::b5) by BYAPR07CA0054.outlook.office365.com (2603:10b6:a03:60::31) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9846.30 via Frontend Transport; Thu, 30 Apr 2026 14:46:31 +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 SJ1PEPF00002323.mail.protection.outlook.com (10.167.242.85) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.18 via Frontend Transport; Thu, 30 Apr 2026 14:46:29 +0000 Received: from DFLE204.ent.ti.com (10.64.6.62) by flwvzet200.ext.ti.com (10.248.192.31) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Thu, 30 Apr 2026 09:46:26 -0500 Received: from DFLE208.ent.ti.com (10.64.6.66) by DFLE204.ent.ti.com (10.64.6.62) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Thu, 30 Apr 2026 09:46:26 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) by DFLE208.ent.ti.com (10.64.6.66) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Thu, 30 Apr 2026 09:46:26 -0500 Received: from LTPW0EX92E.dhcp.ti.com (ltpw0ex92e.dhcp.ti.com [10.82.30.14]) by lelvem-mr06.itg.ti.com (8.18.1/8.18.1) with ESMTP id 63UEk6Mj1332278; Thu, 30 Apr 2026 09:46:20 -0500 From: Niranjan H Y To: CC: , , , , , , , , , , , , , , , , Niranjan H Y Subject: [PATCH v14 2/4] ASoC: tac5xx2-sdw: add soundwire based codec driver Date: Thu, 30 Apr 2026 20:15:52 +0530 Message-ID: <20260430144554.1335-3-niranjan.hy@ti.com> X-Mailer: git-send-email 2.33.0.windows.2 In-Reply-To: <20260430144554.1335-1-niranjan.hy@ti.com> References: <20260430144554.1335-1-niranjan.hy@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: SJ1PEPF00002323:EE_|SA1PR10MB7553:EE_ X-MS-Office365-Filtering-Correlation-Id: af65fa74-fa7e-464d-d705-08dea6c743cf X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|36860700016|82310400026|376014|7416014|1800799024|13003099007|18002099003|56012099003|22082099003; X-Microsoft-Antispam-Message-Info: NaW9XavUDndb+Ya67Z49iVmYQKRcNXrxyQxddvNLN6yZifJnWH/1NiWqNBtdzJmzEBE77ci2rMjod/yWd/HdWVI92L7kW7n0NyA/1dOwoQkwF29yKyh1p/jS4G95yPTN+WCNip78XPORrTTaPNGdErk4LsGh0OioOMOPjrt296m2NkfrjONYGGVwQxCcikSwuAs4cEyKq13NRqjIMcnCRTjkbalwihygmvDyFOKjz7a1l6Xj+B5tIHpeEPgxjegXQ4d7DOv6b3XDylsbA+vJNQuIeXulFc5ihGcyoRo4Y0v09ryK3pznwfl1/fxxyM7SgYhvV4sPck1atLb9nML90w9ISm5IYhF4k/ziaqrYj0NX/FCBI+bX6F03/SLby6sAdqIPq3BPkmkJTONCnNklW8NHlIt9wz6ZV1mypS9Nj93EtSEbd1ocDZhDJed1qZ0H6QhjtU5tl6Pgvm3qZyGlIp2Lvd0Gdsw32lyjZNlZUAvN7NYwUUH6ZiZs2HF3XZfjwsEZqapS98pTVdZEHpzkp48OB9wcRiHKzc/Q7rRfYLno2/zf3uwM9OF/s5NDJ/Gg8iY96HQDDFQFDM5GslobH2xcqNN2rZ3pP/76SDrC/JAgUmse3xVEPh6X0jy0j87XI2gk+PbJA8oDSsq8g+yPm0H0BcMSXT0mCcURvbRwDTOAWTqFqaFBqHutX0u0IFza/ZI4e6cbkagDtVPrXXjmgh3R6hNI+coNDaRixfU8E9w= X-Forefront-Antispam-Report: CIP:198.47.21.194;CTRY:US;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:flwvzet200.ext.ti.com;PTR:ErrorRetry;CAT:NONE;SFS:(13230040)(36860700016)(82310400026)(376014)(7416014)(1800799024)(13003099007)(18002099003)(56012099003)(22082099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: Vb1DXT7JgX4WfLIgCid9H1qGXz3p5VikYdm/SpdayoQqAyENekhxE479R9yycJ7ucU1C4FMLbwCFdvu3EDtOXrNSCqV/o78o9ZEQYRSExDI6d6uNZZpaWhsXv7nWt8JmIe/orj1L7OvFLZluQhlYTpBNwgnrlkir0jArgYabtBNTnYOeUS/bxac/DZXg07uUU4/Li4ZE3lnjn3vSoJyUuPLhPNsPe6xBadyMGRBjNErs6SKWzwfpaXU3phS95kLn2/LU5ogLQShxGteMXGGFUC2yfZTNzRsEuj/+AWgmq9iwOc/u0v1heSSnC5DQxqlmwkVDrbkF0RPtcDrUbePs6fxiyp2gA1NUHAZC6a61aCx+8NoQdcLnx0kw2ROL89E5atap1+KAMjtHxDg3PVDZy0+qZ+0f4OtjZUwcCWv0C9hSh8R1fl5xehJn3rgGemvj X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Apr 2026 14:46:29.8295 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: af65fa74-fa7e-464d-d705-08dea6c743cf 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: SJ1PEPF00002323.namprd03.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SA1PR10MB7553 Add codec driver for tac5xx2 family of devices. This includes the support for 1. tac5572 - DAC, PDM, UAJ and HID 2. tas2883 - Amplifier with DSP 3. tac5672 - Similar to tac5572 with feedback 4. tac5682 - Similar to tac5672 with Amplifier DSP. Signed-off-by: Niranjan H Y --- v14: - Resending complete series (v13 1/4 was accidentally sent alone) - rename the first_hw_init to first_hw_init_done for readability. - drop uaj_lock to make it simiar to other drivers - move the pm_runtime_enable to probe and keep only pm_runtime_set_active for first attach case. - call pm_runtime_get_sync and pm_runtime_put_autosuspend in .set_jack - handle early call to .set_jack when is it called before first "attach" - remove tac5xx2_sdw_clk_stop as currently it is dummy - nit-pick in .hw_free to use xmas tree v13: - no change (this patch was not sent as part of v13 series) v12: - remove check for hw_init in the .set_jack and let regcache handle the device writes correcty. - add missing pm_rutime_disable in the .remove callback - improve error logging in .hw_params and .hw_free for pde entities - improve .hw_free to throw error for unknown dai id - include part_id in the firmware binary name to avoid potential name collision while using multiple codecs which doesn't have unqiue_id - updated firmware header parsing to include updated header and log debug information. v11: - refactor code for resume to wait for the initialisation to complete and then proceed. - replace the sdca_asoc_set_pde_pool_sync with sdca_asoc_pde_poll_actual_ps v10: - use sdca helper sdca_asoc_set_pde_poll_sync for changing the power states. - register .set_jack callback only for if uaj is available. v9: - Update tac5xx2-sdw.c hw_params() and hw_free() to use new SDCA helper sdca_asoc_pde_ensure_ps - Remove redundant PPU11 initialization as it is there as part of the initialisation table. - remove unnecessary default value writes for latch clear as the register. - Improve jack detection and PDE power state transition comments v8: - disable interrupts in .set_jack if jack is set to NULL - hold uaj_lock in .set_jack - remove unwanted interrupt enable in initialisation v7: - refactor remove the cx11, cs18 and cs11 they are not required to be configured for mic - fix error handling and interrupt cleanup in .set_jack - fix typo in Kconfig v6: - move firmware caching trigger from soundwire bus callback to soundwire probe and make it asynchronous - validate the firmware fully before starting firmware. - drop mixer control for cx11 configuration - check the actual power state in .hw_free after requesting power state transition to power off - use dev_is_pci() and remove CONFIG_PCI v5: - add missing pde_lock while accessing the current power state. - add uaj_lock to serialize uaj detection update - return error, if any, returned by sdw_stream_add_slave in hw_parms - drop snd_soc_unregister_component as we are using devm_snd_soc_register_component - fix issue in error handling for invalid firmware - remove unsupported line in/out detection in jack detection - refactor the jack and button detection logic to be based on their respective interrupt v4: - make volume controls as stereo controls for amp gain, playback, dmic and uaj playback. - better error handling for "CX11 CS Select" mixer control. - use switch statement for scalability in hw_params and hw_free - remove unnecessary else in tac_io_init - change error log for unsupported sample rates to debug logs - make firmware binary parsing robust by checking the fw size during caching and parsing v3: - use macro SDCA_SINGLE_Q78_TLV for the volume mixer controls - replace magic number with macro for current owner - fix debug log message about the current owner for hid event v2: - Define and use consistent macros for register access to improve code =C2=A0 readability and maintainability - Replace complex event handlers with simpler DAPM widget implementations =C2=A0 using direct register control for muting/unmuting and enabling/disab= ling =C2=A0 components - Replace custom volume controls with standard Q7.8 controls from the =C2=A0 SDCA framework - Fix PDE power state transitions with proper verification of actual power = state - Combine separate locks into a single ops\_lock to protect both firmware =C2=A0 operations and power state transitions - Clean up interrupt handling by removing unnecessary register accesses - Fix headset microphone control by using the correct mono channel value - Add comments to clarify firmware handling and critical sections --- sound/soc/codecs/Kconfig | 11 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tac5xx2-sdw.c | 2057 ++++++++++++++++++++++++++++++++ sound/soc/codecs/tac5xx2.h | 259 ++++ 4 files changed, 2329 insertions(+) create mode 100644 sound/soc/codecs/tac5xx2-sdw.c create mode 100644 sound/soc/codecs/tac5xx2.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c43861b7d..069ec05e4 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -264,6 +264,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_STA529 imply SND_SOC_STAC9766 imply SND_SOC_STI_SAS + imply SND_SOC_TAC5XX2_SDW imply SND_SOC_TAS2552 imply SND_SOC_TAS2562 imply SND_SOC_TAS2764 @@ -2140,6 +2141,16 @@ config SND_SOC_STAC9766 config SND_SOC_STI_SAS tristate "codec Audio support for STI SAS codec" =20 +config SND_SOC_TAC5XX2_SDW + tristate "Texas Instruments TAC5XX2 SoundWire Smart Amplifier" + depends on SOUNDWIRE + depends on SND_SOC_SDCA + help + This option enables support for Texas Instruments TAC5XX2 family + of SoundWire Smart Amplifiers. This includes TAC5572, TAC5672, + TAC5682 and TAS2883. To compile this driver as a module, choose + M here: the module will be called snd-soc-tac5xx2. + config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 106fdc140..2c2d0553f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -313,6 +313,7 @@ snd-soc-sta350-y :=3D sta350.o snd-soc-sta529-y :=3D sta529.o snd-soc-stac9766-y :=3D stac9766.o snd-soc-sti-sas-y :=3D sti-sas.o +snd-soc-tac5xx2-sdw-y :=3D tac5xx2-sdw.o snd-soc-tas5086-y :=3D tas5086.o snd-soc-tas571x-y :=3D tas571x.o snd-soc-tas5720-y :=3D tas5720.o @@ -747,6 +748,7 @@ obj-$(CONFIG_SND_SOC_STA350) +=3D snd-soc-sta350.o obj-$(CONFIG_SND_SOC_STA529) +=3D snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) +=3D snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_STI_SAS) +=3D snd-soc-sti-sas.o +obj-$(CONFIG_SND_SOC_TAC5XX2_SDW) +=3D snd-soc-tac5xx2-sdw.o obj-$(CONFIG_SND_SOC_TAS2552) +=3D snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS2562) +=3D snd-soc-tas2562.o obj-$(CONFIG_SND_SOC_TAS2764) +=3D snd-soc-tas2764.o diff --git a/sound/soc/codecs/tac5xx2-sdw.c b/sound/soc/codecs/tac5xx2-sdw.c new file mode 100644 index 000000000..402053451 --- /dev/null +++ b/sound/soc/codecs/tac5xx2-sdw.c @@ -0,0 +1,2057 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// ALSA SoC Texas Instruments TAC5XX2 Audio Smart Amplifier +// +// Copyright (C) 2025 Texas Instruments Incorporated +// https://www.ti.com +// +// Author: Niranjan H Y + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tac5xx2.h" + +#define TAC5XX2_PROBE_TIMEOUT_MS 3000 +#define TAC5XX2_FW_CACHE_TIMEOUT_MS 300 + +#define TAC5XX2_DEVICE_RATES (SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000 | \ + SNDRV_PCM_RATE_88200) +#define TAC5XX2_DEVICE_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) +/* Define channel constants */ +#define TAC_CHANNEL_LEFT 1 +#define TAC_CHANNEL_RIGHT 2 +#define TAC_JACK_MONO_CS 2 + +#define TAC_MUTE_REG(func, fu, ch) \ + SDW_SDCA_CTL(TAC_FUNCTION_ID_##func, TAC_SDCA_ENT_##fu, \ + TAC_SDCA_CHANNEL_MUTE, TAC_CHANNEL_##ch) +#define TAC_USAGE_REG(func, ent) \ + SDW_SDCA_CTL(TAC_FUNCTION_ID_##func, TAC_SDCA_ENT_##ent, \ + TAC_SDCA_CTL_USAGE, 0) +#define TAC_XU_BYPASS_REG(func, xu) \ + SDW_SDCA_CTL(TAC_FUNCTION_ID_##func, TAC_SDCA_ENT_##xu, \ + TAC_SDCA_CTL_XU_BYPASS, 0) + +/* mute registers */ +#define FU21_L_MUTE_REG TAC_MUTE_REG(SA, FU21, LEFT) +#define FU21_R_MUTE_REG TAC_MUTE_REG(SA, FU21, RIGHT) +#define FU23_L_MUTE_REG TAC_MUTE_REG(SA, FU23, LEFT) +#define FU23_R_MUTE_REG TAC_MUTE_REG(SA, FU23, RIGHT) +#define FU26_MUTE_REG TAC_MUTE_REG(SA, FU26, LEFT) +#define FU11_L_MUTE_REG TAC_MUTE_REG(SM, FU11, LEFT) +#define FU11_R_MUTE_REG TAC_MUTE_REG(SM, FU11, RIGHT) +#define FU113_L_MUTE_REG TAC_MUTE_REG(SM, FU113, LEFT) +#define FU113_R_MUTE_REG TAC_MUTE_REG(SM, FU113, RIGHT) +#define FU41_L_MUTE_REG TAC_MUTE_REG(UAJ, FU41, LEFT) +#define FU41_R_MUTE_REG TAC_MUTE_REG(UAJ, FU41, RIGHT) +#define FU36_MUTE_REG TAC_MUTE_REG(UAJ, FU36, RIGHT) + +/* it/ot usage */ +#define IT11_USAGE_REG TAC_USAGE_REG(SM, IT11) +#define IT41_USAGE_REG TAC_USAGE_REG(UAJ, IT41) +#define IT33_USAGE_REG TAC_USAGE_REG(UAJ, IT33) +#define OT113_USAGE_REG TAC_USAGE_REG(SM, OT113) +#define OT45_USAGE_REG TAC_USAGE_REG(UAJ, OT45) +#define OT36_USAGE_REG TAC_USAGE_REG(UAJ, OT36) + +/* xu bypass */ +#define XU12_BYPASS_REG TAC_XU_BYPASS_REG(SM, XU12) +#define XU42_BYPASS_REG TAC_XU_BYPASS_REG(UAJ, XU42) + +#define TAC_DSP_ALGO_STATUS TAC_REG_SDW(0, 3, 12) +#define TAC_DSP_ALGO_STATUS_RUNNING 0x20 +#define TAC_FW_HDR_SIZE 88 +#define TAC_FW_FILE_HDR 20 +#define TAC_MAX_FW_CHUNKS 512 + +struct tac_fw_hdr { + u32 size; + u32 version_offset; + u32 plt_id; + u32 ppc3_ver; + u64 timestamp; + u8 ddc_name[64]; +}; + +/* Firmware file/chunk structure */ +struct tac_fw_file { + u32 vendor_id; + u32 file_id; + u32 version; + u32 length; + u32 dest_addr; + u8 *fw_data; +}; + +/* TLV for volume control */ +static const DECLARE_TLV_DB_SCALE(tac5xx2_amp_tlv, 0, 50, 0); +static const DECLARE_TLV_DB_SCALE(tac5xx2_dvc_tlv, -7200, 50, 0); + +/* Q7.8 volume control parameters: range -72dB to +6dB, step 0.5dB */ +#define TAC_DVC_STEP 128 /* 0.5 dB in Q7.8 format */ +#define TAC_DVC_MIN (-144) /* -72 dB / 0.5 dB step */ +#define TAC_DVC_MAX 12 /* +6 dB / 0.5 dB step */ + +/* TAC-specific stereo volume control macro using SDW_SDCA_CTL (single con= trol for L/R) */ +#define TAC_DOUBLE_Q78_TLV(name, func_id, ent_id) \ + SDCA_DOUBLE_Q78_TLV(name, \ + SDW_SDCA_CTL(TAC_FUNCTION_ID_##func_id, TAC_SDCA_ENT_##ent_id, \ + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), \ + SDW_SDCA_CTL(TAC_FUNCTION_ID_##func_id, TAC_SDCA_ENT_##ent_id, \ + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), \ + TAC_DVC_MIN, TAC_DVC_MAX, TAC_DVC_STEP, tac5xx2_dvc_tlv) + +struct tac5xx2_prv { + struct snd_soc_component *component; + struct sdw_slave *sdw_peripheral; + struct sdca_function_data *sa_func_data; + struct sdca_function_data *sm_func_data; + struct sdca_function_data *uaj_func_data; + struct sdca_function_data *hid_func_data; + enum sdw_slave_status status; + struct regmap *regmap; + struct device *dev; + bool hw_init; + bool first_hw_init_done; + u32 part_id; + struct snd_soc_jack *hs_jack; + int jack_type; + /* Custom fw binary. UMP File Download is not used. */ + unsigned int fw_file_cnt; + struct tac_fw_file *fw_files; + struct completion fw_caching_complete; + bool fw_dl_success; + u8 fw_binaryname[64]; +}; + +static const struct reg_default tac_reg_default[] =3D { + {TAC_SW_RESET, 0x0}, + {TAC_SLEEP_MODEZ, 0x0}, + {TAC_FEATURE_PDZ, 0x0}, + {TAC_TX_CH_EN, 0xf0}, + {TAC_REG_SDW(0, 0, 0x5), 0xcf}, + {TAC_REG_SDW(0, 0, 0x6), 0xa}, + {TAC_REG_SDW(0, 0, 0x7), 0x0}, + {TAC_REG_SDW(0, 0, 0x8), 0xfe}, + {TAC_REG_SDW(0, 0, 0x9), 0x9}, + {TAC_REG_SDW(0, 0, 0xa), 0x28}, + {TAC_REG_SDW(0, 0, 0xb), 0x1}, + {TAC_REG_SDW(0, 0, 0xc), 0x11}, + {TAC_REG_SDW(0, 0, 0xd), 0x11}, + {TAC_REG_SDW(0, 0, 0xe), 0x61}, + {TAC_REG_SDW(0, 0, 0xf), 0x0}, + {TAC_REG_SDW(0, 0, 0x10), 0x50}, + {TAC_REG_SDW(0, 0, 0x11), 0x70}, + {TAC_REG_SDW(0, 0, 0x12), 0x60}, + {TAC_REG_SDW(0, 0, 0x13), 0x28}, + {TAC_REG_SDW(0, 0, 0x14), 0x0}, + {TAC_REG_SDW(0, 0, 0x15), 0x18}, + {TAC_REG_SDW(0, 0, 0x16), 0x20}, + {TAC_REG_SDW(0, 0, 0x17), 0x0}, + {TAC_REG_SDW(0, 0, 0x18), 0x18}, + {TAC_REG_SDW(0, 0, 0x19), 0x54}, + {TAC_REG_SDW(0, 0, 0x1a), 0x8}, + {TAC_REG_SDW(0, 0, 0x1b), 0x0}, + {TAC_REG_SDW(0, 0, 0x1c), 0x30}, + {TAC_REG_SDW(0, 0, 0x1d), 0x0}, + {TAC_REG_SDW(0, 0, 0x1e), 0x0}, + {TAC_REG_SDW(0, 0, 0x1f), 0x0}, + {TAC_REG_SDW(0, 0, 0x20), 0x0}, + {TAC_REG_SDW(0, 0, 0x21), 0x20}, + {TAC_REG_SDW(0, 0, 0x22), 0x21}, + {TAC_REG_SDW(0, 0, 0x23), 0x22}, + {TAC_REG_SDW(0, 0, 0x24), 0x23}, + {TAC_REG_SDW(0, 0, 0x25), 0x4}, + {TAC_REG_SDW(0, 0, 0x26), 0x5}, + {TAC_REG_SDW(0, 0, 0x27), 0x6}, + {TAC_REG_SDW(0, 0, 0x28), 0x7}, + {TAC_REG_SDW(0, 0, 0x29), 0x0}, + {TAC_REG_SDW(0, 0, 0x2a), 0x0}, + {TAC_REG_SDW(0, 0, 0x2b), 0x0}, + {TAC_REG_SDW(0, 0, 0x2c), 0x20}, + {TAC_REG_SDW(0, 0, 0x2d), 0x21}, + {TAC_REG_SDW(0, 0, 0x2e), 0x2}, + {TAC_REG_SDW(0, 0, 0x2f), 0x3}, + {TAC_REG_SDW(0, 0, 0x30), 0x4}, + {TAC_REG_SDW(0, 0, 0x31), 0x5}, + {TAC_REG_SDW(0, 0, 0x32), 0x6}, + {TAC_REG_SDW(0, 0, 0x33), 0x7}, + {TAC_REG_SDW(0, 0, 0x34), 0x0}, + {TAC_REG_SDW(0, 0, 0x35), 0x90}, + {TAC_REG_SDW(0, 0, 0x36), 0x80}, + {TAC_REG_SDW(0, 0, 0x37), 0x0}, + {TAC_REG_SDW(0, 0, 0x39), 0x0}, + {TAC_REG_SDW(0, 0, 0x3a), 0x90}, + {TAC_REG_SDW(0, 0, 0x3b), 0x80}, + {TAC_REG_SDW(0, 0, 0x3c), 0x0}, + {TAC_REG_SDW(0, 0, 0x3e), 0x0}, + {TAC_REG_SDW(0, 0, 0x3f), 0x90}, + {TAC_REG_SDW(0, 0, 0x40), 0x80}, + {TAC_REG_SDW(0, 0, 0x41), 0x0}, + {TAC_REG_SDW(0, 0, 0x43), 0x90}, + {TAC_REG_SDW(0, 0, 0x44), 0x80}, + {TAC_REG_SDW(0, 0, 0x45), 0x0}, + {TAC_REG_SDW(0, 0, 0x47), 0x90}, + {TAC_REG_SDW(0, 0, 0x48), 0x80}, + {TAC_REG_SDW(0, 0, 0x49), 0x0}, + {TAC_REG_SDW(0, 0, 0x4b), 0x90}, + {TAC_REG_SDW(0, 0, 0x4c), 0x80}, + {TAC_REG_SDW(0, 0, 0x4d), 0x0}, + {TAC_REG_SDW(0, 0, 0x4f), 0x31}, + {TAC_REG_SDW(0, 0, 0x50), 0x0}, + {TAC_REG_SDW(0, 0, 0x51), 0x0}, + {TAC_REG_SDW(0, 0, 0x52), 0x90}, + {TAC_REG_SDW(0, 0, 0x53), 0x80}, + {TAC_REG_SDW(0, 0, 0x55), 0x90}, + {TAC_REG_SDW(0, 0, 0x56), 0x80}, + {TAC_REG_SDW(0, 0, 0x58), 0x90}, + {TAC_REG_SDW(0, 0, 0x59), 0x80}, + {TAC_REG_SDW(0, 0, 0x5b), 0x90}, + {TAC_REG_SDW(0, 0, 0x5c), 0x80}, + {TAC_REG_SDW(0, 0, 0x5e), 0x8}, + {TAC_REG_SDW(0, 0, 0x5f), 0x8}, + {TAC_REG_SDW(0, 0, 0x60), 0x0}, + {TAC_REG_SDW(0, 0, 0x61), 0x0}, + {TAC_REG_SDW(0, 0, 0x62), 0xff}, + {TAC_REG_SDW(0, 0, 0x63), 0xc0}, + {TAC_REG_SDW(0, 0, 0x64), 0x5}, + {TAC_REG_SDW(0, 0, 0x65), 0x3}, + {TAC_REG_SDW(0, 0, 0x66), 0x0}, + {TAC_REG_SDW(0, 0, 0x67), 0x0}, + {TAC_REG_SDW(0, 0, 0x68), 0x0}, + {TAC_REG_SDW(0, 0, 0x69), 0x8}, + {TAC_REG_SDW(0, 0, 0x6a), 0x0}, + {TAC_REG_SDW(0, 0, 0x6b), 0xa0}, + {TAC_REG_SDW(0, 0, 0x6c), 0x18}, + {TAC_REG_SDW(0, 0, 0x6d), 0x18}, + {TAC_REG_SDW(0, 0, 0x6e), 0x18}, + {TAC_REG_SDW(0, 0, 0x6f), 0x18}, + {TAC_REG_SDW(0, 0, 0x70), 0x88}, + {TAC_REG_SDW(0, 0, 0x71), 0xff}, + {TAC_REG_SDW(0, 0, 0x72), 0x0}, + {TAC_REG_SDW(0, 0, 0x73), 0x31}, + {TAC_REG_SDW(0, 0, 0x74), 0xc0}, + {TAC_REG_SDW(0, 0, 0x75), 0x0}, + {TAC_REG_SDW(0, 0, 0x76), 0x0}, + {TAC_REG_SDW(0, 0, 0x77), 0x0}, + {TAC_REG_SDW(0, 0, 0x78), 0x0}, + {TAC_REG_SDW(0, 0, 0x7b), 0x0}, + {TAC_REG_SDW(0, 0, 0x7c), 0xd0}, + {TAC_REG_SDW(0, 0, 0x7d), 0x0}, + {TAC_REG_SDW(0, 0, 0x7e), 0x0}, + {TAC_REG_SDW(0, 1, 0x1), 0x0}, + {TAC_REG_SDW(0, 1, 0x2), 0x0}, + {TAC_REG_SDW(0, 1, 0x3), 0x0}, + {TAC_REG_SDW(0, 1, 0x4), 0x4}, + {TAC_REG_SDW(0, 1, 0x5), 0x0}, + {TAC_REG_SDW(0, 1, 0x6), 0x0}, + {TAC_REG_SDW(0, 1, 0x7), 0x0}, + {TAC_REG_SDW(0, 1, 0x8), 0x0}, + {TAC_REG_SDW(0, 1, 0x9), 0x0}, + {TAC_REG_SDW(0, 1, 0xa), 0x0}, + {TAC_REG_SDW(0, 1, 0xb), 0x1}, + {TAC_REG_SDW(0, 1, 0xc), 0x0}, + {TAC_REG_SDW(0, 1, 0xd), 0x0}, + {TAC_REG_SDW(0, 1, 0xe), 0x0}, + {TAC_REG_SDW(0, 1, 0xf), 0x8}, + {TAC_REG_SDW(0, 1, 0x10), 0x0}, + {TAC_REG_SDW(0, 1, 0x11), 0x0}, + {TAC_REG_SDW(0, 1, 0x12), 0x1}, + {TAC_REG_SDW(0, 1, 0x13), 0x0}, + {TAC_REG_SDW(0, 1, 0x14), 0x0}, + {TAC_REG_SDW(0, 1, 0x15), 0x0}, + {TAC_REG_SDW(0, 1, 0x16), 0x0}, + {TAC_REG_SDW(0, 1, 0x17), 0x0}, + {TAC_REG_SDW(0, 1, 0x18), 0x0}, + {TAC_REG_SDW(0, 1, 0x19), 0x0}, + {TAC_REG_SDW(0, 1, 0x1a), 0x0}, + {TAC_REG_SDW(0, 1, 0x1b), 0x0}, + {TAC_REG_SDW(0, 1, 0x1c), 0x0}, + {TAC_REG_SDW(0, 1, 0x1d), 0x0}, + {TAC_REG_SDW(0, 1, 0x1e), 0x2}, + {TAC_REG_SDW(0, 1, 0x1f), 0x8}, + {TAC_REG_SDW(0, 1, 0x20), 0x9}, + {TAC_REG_SDW(0, 1, 0x21), 0xa}, + {TAC_REG_SDW(0, 1, 0x22), 0xb}, + {TAC_REG_SDW(0, 1, 0x23), 0xc}, + {TAC_REG_SDW(0, 1, 0x24), 0xd}, + {TAC_REG_SDW(0, 1, 0x25), 0xe}, + {TAC_REG_SDW(0, 1, 0x26), 0xf}, + {TAC_REG_SDW(0, 1, 0x27), 0x8}, + {TAC_REG_SDW(0, 1, 0x28), 0x9}, + {TAC_REG_SDW(0, 1, 0x29), 0xa}, + {TAC_REG_SDW(0, 1, 0x2a), 0xb}, + {TAC_REG_SDW(0, 1, 0x2b), 0xc}, + {TAC_REG_SDW(0, 1, 0x2c), 0xd}, + {TAC_REG_SDW(0, 1, 0x2d), 0xe}, + {TAC_REG_SDW(0, 1, 0x2e), 0xf}, + {TAC_REG_SDW(0, 1, 0x2f), 0x0}, + {TAC_REG_SDW(0, 1, 0x30), 0x0}, + {TAC_REG_SDW(0, 1, 0x31), 0x0}, + {TAC_REG_SDW(0, 1, 0x32), 0x0}, + {TAC_REG_SDW(0, 1, 0x33), 0x0}, + {TAC_REG_SDW(0, 1, 0x34), 0x0}, + {TAC_REG_SDW(0, 1, 0x35), 0x0}, + {TAC_REG_SDW(0, 1, 0x36), 0x0}, + {TAC_REG_SDW(0, 1, 0x37), 0x0}, + {TAC_REG_SDW(0, 1, 0x38), 0x98}, + {TAC_REG_SDW(0, 1, 0x39), 0x0}, + {TAC_REG_SDW(0, 1, 0x3a), 0x0}, + {TAC_REG_SDW(0, 1, 0x3b), 0x0}, + {TAC_REG_SDW(0, 1, 0x3c), 0x1}, + {TAC_REG_SDW(0, 1, 0x3d), 0x2}, + {TAC_REG_SDW(0, 1, 0x3e), 0x3}, + {TAC_REG_SDW(0, 1, 0x3f), 0x4}, + {TAC_REG_SDW(0, 1, 0x40), 0x5}, + {TAC_REG_SDW(0, 1, 0x41), 0x6}, + {TAC_REG_SDW(0, 1, 0x42), 0x7}, + {TAC_REG_SDW(0, 1, 0x43), 0x0}, + {TAC_REG_SDW(0, 1, 0x44), 0x0}, + {TAC_REG_SDW(0, 1, 0x45), 0x1}, + {TAC_REG_SDW(0, 1, 0x46), 0x2}, + {TAC_REG_SDW(0, 1, 0x47), 0x3}, + {TAC_REG_SDW(0, 1, 0x48), 0x4}, + {TAC_REG_SDW(0, 1, 0x49), 0x5}, + {TAC_REG_SDW(0, 1, 0x4a), 0x6}, + {TAC_REG_SDW(0, 1, 0x4b), 0x7}, + {TAC_REG_SDW(0, 1, 0x4c), 0x98}, + {TAC_REG_SDW(0, 1, 0x4d), 0x0}, + {TAC_REG_SDW(0, 1, 0x4e), 0x0}, + {TAC_REG_SDW(0, 1, 0x4f), 0x0}, + {TAC_REG_SDW(0, 1, 0x50), 0x1}, + {TAC_REG_SDW(0, 1, 0x51), 0x2}, + {TAC_REG_SDW(0, 1, 0x52), 0x3}, + {TAC_REG_SDW(0, 1, 0x53), 0x4}, + {TAC_REG_SDW(0, 1, 0x54), 0x5}, + {TAC_REG_SDW(0, 1, 0x55), 0x6}, + {TAC_REG_SDW(0, 1, 0x56), 0x7}, + {TAC_REG_SDW(0, 1, 0x57), 0x0}, + {TAC_REG_SDW(0, 1, 0x58), 0x0}, + {TAC_REG_SDW(0, 1, 0x59), 0x1}, + {TAC_REG_SDW(0, 1, 0x5a), 0x2}, + {TAC_REG_SDW(0, 1, 0x5b), 0x3}, + {TAC_REG_SDW(0, 1, 0x5c), 0x4}, + {TAC_REG_SDW(0, 1, 0x5d), 0x5}, + {TAC_REG_SDW(0, 1, 0x5e), 0x6}, + {TAC_REG_SDW(0, 1, 0x5f), 0x7}, + {TAC_REG_SDW(0, 1, 0x60), 0x98}, + {TAC_REG_SDW(0, 1, 0x61), 0x0}, + {TAC_REG_SDW(0, 1, 0x62), 0x0}, + {TAC_REG_SDW(0, 1, 0x63), 0x0}, + {TAC_REG_SDW(0, 1, 0x64), 0x1}, + {TAC_REG_SDW(0, 1, 0x65), 0x2}, + {TAC_REG_SDW(0, 1, 0x66), 0x3}, + {TAC_REG_SDW(0, 1, 0x67), 0x4}, + {TAC_REG_SDW(0, 1, 0x68), 0x5}, + {TAC_REG_SDW(0, 1, 0x69), 0x6}, + {TAC_REG_SDW(0, 1, 0x6a), 0x7}, + {TAC_REG_SDW(0, 1, 0x6b), 0x0}, + {TAC_REG_SDW(0, 1, 0x6c), 0x0}, + {TAC_REG_SDW(0, 1, 0x6d), 0x1}, + {TAC_REG_SDW(0, 1, 0x6e), 0x2}, + {TAC_REG_SDW(0, 1, 0x6f), 0x3}, + {TAC_REG_SDW(0, 1, 0x70), 0x4}, + {TAC_REG_SDW(0, 1, 0x71), 0x5}, + {TAC_REG_SDW(0, 1, 0x72), 0x6}, + {TAC_REG_SDW(0, 1, 0x73), 0x7}, +}; + +static const struct reg_sequence tac_spk_seq[] =3D { + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU21, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU21, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), +}; + +static const struct reg_sequence tac_sm_seq[] =3D { + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), +}; + +static const struct reg_sequence tac_uaj_seq[] =3D { + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT), 0), + REG_SEQ0(SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU36, + TAC_SDCA_CHANNEL_GAIN, TAC_JACK_MONO_CS), 0), +}; + +static bool tac_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAC_REG_SDW(0, 0, 1) ... TAC_REG_SDW(0, 0, 5): + case TAC_REG_SDW(0, 2, 1) ... TAC_REG_SDW(0, 2, 6): + case TAC_REG_SDW(0, 2, 24) ... TAC_REG_SDW(0, 2, 55): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_HID, TAC_SDCA_ENT_HID1, + TAC_SDCA_CTL_HIDTX_CURRENT_OWNER, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_HID, TAC_SDCA_ENT_HID1, + TAC_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35, + TAC_SDCA_CTL_DET_MODE, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_PDE23, + TAC_SDCA_REQUESTED_PS, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_PDE11, + TAC_SDCA_REQUESTED_PS, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_PDE47, + TAC_SDCA_REQUESTED_PS, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_PDE34, + TAC_SDCA_REQUESTED_PS, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_PDE23, + TAC_SDCA_ACTUAL_PS, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_PDE11, + TAC_SDCA_ACTUAL_PS, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_PDE47, + TAC_SDCA_ACTUAL_PS, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_PDE34, + TAC_SDCA_ACTUAL_PS, 0): + case SDW_SCP_SDCA_INT1: + case SDW_SCP_SDCA_INT2: + case SDW_SCP_SDCA_INT3: + case SDW_SCP_SDCA_INT4: + case SDW_SDCA_CTL(1, 0, 0x10, 0): + case SDW_SDCA_CTL(2, 0, 0x10, 0): + case SDW_SDCA_CTL(3, 0, 0x10, 0): + case SDW_SDCA_CTL(4, 0, 0x1, 0): + case 0x44007F80 ... 0x44007F87: + case TAC_DSP_ALGO_STATUS: /* DSP algo status - always read from HW */ + return true; + default: + break; + } + + return false; +} + +static int tac_sdca_mbq_size(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU21, + TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_LEFT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU21, + TAC_SDCA_CHANNEL_VOLUME, TAC_CHANNEL_RIGHT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SA, TAC_SDCA_ENT_FU23, + TAC_SDCA_MASTER_GAIN, 0): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU113, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_SM, TAC_SDCA_ENT_FU11, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_LEFT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU41, + TAC_SDCA_CHANNEL_GAIN, TAC_CHANNEL_RIGHT): + case SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU36, + TAC_SDCA_CHANNEL_GAIN, TAC_JACK_MONO_CS): + return 2; + + default: + return 1; + } +} + +static const struct regmap_sdw_mbq_cfg tac_mbq_cfg =3D { + .mbq_size =3D tac_sdca_mbq_size, +}; + +static const struct regmap_config tac_regmap =3D { + .reg_bits =3D 32, + .val_bits =3D 16, /* mbq support */ + .reg_defaults =3D tac_reg_default, + .num_reg_defaults =3D ARRAY_SIZE(tac_reg_default), + .max_register =3D 0x47FFFFFF, + .cache_type =3D REGCACHE_MAPLE, + .volatile_reg =3D tac_volatile_reg, + .use_single_read =3D true, + .use_single_write =3D true, +}; + +/* Check if device has DSP algo that needs status monitoring */ +static bool tac_has_dsp_algo(struct tac5xx2_prv *tac_dev) +{ + switch (tac_dev->part_id) { + case 0x5682: + case 0x2883: + return true; + default: + return false; + } +} + +/* Check if device has UAJ (Universal Audio Jack) support */ +static bool tac_has_uaj_support(struct tac5xx2_prv *tac_dev) +{ + return tac_dev->uaj_func_data; +} + +/* Forward declaration for headset detection */ +static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev); + +/* Volume controls for mic, hp and mic cap */ +static const struct snd_kcontrol_new tac5xx2_snd_controls[] =3D { + SOC_DOUBLE_R_RANGE_TLV("Amp Volume", TAC_AMP_LVL_CFG0, TAC_AMP_LVL_CFG1, + 2, 0, 44, 1, tac5xx2_amp_tlv), + TAC_DOUBLE_Q78_TLV("DMIC Capture Volume", SM, FU113), + TAC_DOUBLE_Q78_TLV("Speaker Volume", SA, FU21), +}; + +static const struct snd_kcontrol_new tac_uaj_controls[] =3D { + TAC_DOUBLE_Q78_TLV("UAJ Playback Volume", UAJ, FU41), + SDCA_SINGLE_Q78_TLV("UAJ Capture Volume", + SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_FU36, + TAC_SDCA_CHANNEL_GAIN, TAC_JACK_MONO_CS), + TAC_DVC_MIN, TAC_DVC_MAX, TAC_DVC_STEP, tac5xx2_dvc_tlv), +}; + +static const struct snd_soc_dapm_widget tac5xx2_common_widgets[] =3D { + /* Port 1: Speaker Playback Path */ + SND_SOC_DAPM_AIF_IN("AIF1 Playback", "DP1 Speaker Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("FU21_L", FU21_L_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("FU21_R", FU21_R_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("FU23_L", FU23_L_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("FU23_R", FU23_R_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_OUTPUT("SPK_L"), + SND_SOC_DAPM_OUTPUT("SPK_R"), + + /* Port 3: Smart Mic (DMIC) Capture Path */ + SND_SOC_DAPM_AIF_OUT("AIF3 Capture", "DP3 Mic Capture", 0, SND_SOC_NOPM, = 0, 0), + SND_SOC_DAPM_INPUT("DMIC_L"), + SND_SOC_DAPM_INPUT("DMIC_R"), + SND_SOC_DAPM_PGA("IT11", IT11_USAGE_REG, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CS113", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("FU11_L", FU11_L_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("FU11_R", FU11_R_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("PPU11", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("XU12", XU12_BYPASS_REG, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("FU113_L", FU113_L_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("FU113_R", FU113_R_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("OT113", OT113_USAGE_REG, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_widget tac_uaj_widgets[] =3D { + /* Port 4: UAJ (Headphone) Playback Path */ + SND_SOC_DAPM_AIF_IN("AIF4 Playback", "DP4 UAJ Speaker Playback", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("IT41", IT41_USAGE_REG, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("FU41_L", FU41_L_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("FU41_R", FU41_R_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_PGA("XU42", XU42_BYPASS_REG, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CS41", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_DAC("OT45", "DP4 UAJ Speaker Playback", OT45_USAGE_REG, 0, 0= ), + SND_SOC_DAPM_OUTPUT("HP_L"), + SND_SOC_DAPM_OUTPUT("HP_R"), + + /* Port 7: UAJ (Headset Mic) Capture Path */ + SND_SOC_DAPM_AIF_OUT("AIF7 Capture", "DP7 UAJ Mic Capture", 0, + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("UAJ_MIC"), + SND_SOC_DAPM_ADC("IT33", "DP7 UAJ Mic Capture", IT33_USAGE_REG, 0, 0), + SND_SOC_DAPM_PGA("FU36", FU36_MUTE_REG, 0, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("CS36", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("OT36", OT36_USAGE_REG, 0, 0, NULL, 0), +}; + +static const struct snd_soc_dapm_route tac5xx2_common_routes[] =3D { + /* Speaker Playback Path */ + {"FU21_L", NULL, "AIF1 Playback"}, + {"FU21_R", NULL, "AIF1 Playback"}, + + {"FU23_L", NULL, "FU21_L"}, + {"FU23_R", NULL, "FU21_R"}, + + {"SPK_L", NULL, "FU23_L"}, + {"SPK_R", NULL, "FU23_R"}, + + /* Smart Mic DAPM Routes */ + {"IT11", NULL, "DMIC_L"}, + {"IT11", NULL, "DMIC_R"}, + {"FU11_L", NULL, "IT11"}, + {"FU11_R", NULL, "IT11"}, + {"PPU11", NULL, "FU11_L"}, + {"PPU11", NULL, "FU11_R"}, + {"XU12", NULL, "PPU11"}, + {"FU113_L", NULL, "XU12"}, + {"FU113_R", NULL, "XU12"}, + {"FU113_L", NULL, "CS113"}, + {"FU113_R", NULL, "CS113"}, + {"OT113", NULL, "FU113_L"}, + {"OT113", NULL, "FU113_R"}, + {"OT113", NULL, "CS113"}, + {"AIF3 Capture", NULL, "OT113"}, +}; + +static const struct snd_soc_dapm_route tac_uaj_routes[] =3D { + /* UAJ Playback routes */ + {"IT41", NULL, "AIF4 Playback"}, + {"IT41", NULL, "CS41"}, + {"FU41_L", NULL, "IT41"}, + {"FU41_R", NULL, "IT41"}, + {"XU42", NULL, "FU41_L"}, + {"XU42", NULL, "FU41_R"}, + {"OT45", NULL, "XU42"}, + {"OT45", NULL, "CS41"}, + {"HP_L", NULL, "OT45"}, + {"HP_R", NULL, "OT45"}, + + /* UAJ Capture routes */ + {"IT33", NULL, "UAJ_MIC"}, + {"IT33", NULL, "CS36"}, + {"FU36", NULL, "IT33"}, + {"OT36", NULL, "FU36"}, + {"OT36", NULL, "CS36"}, + {"AIF7 Capture", NULL, "OT36"}, +}; + +static s32 tac_set_sdw_stream(struct snd_soc_dai *dai, + void *sdw_stream, s32 direction) +{ + if (sdw_stream) + snd_soc_dai_dma_data_set(dai, direction, sdw_stream); + + return 0; +} + +static void tac_sdw_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_dai_set_dma_data(dai, substream, NULL); +} + +static int tac_clear_latch(struct tac5xx2_prv *priv) +{ + /* CLR_REG is a self-clearing bit */ + return regmap_update_bits(priv->regmap, TAC_INT_CFG, + TAC_INT_CFG_CLR_REG, TAC_INT_CFG_CLR_REG); +} + +static int tac_sdw_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 tac5xx2_prv *tac_dev =3D snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config =3D {0}; + struct sdw_port_config port_config =3D {0}; + struct sdw_stream_runtime *sdw_stream; + struct sdw_slave *sdw_peripheral =3D tac_dev->sdw_peripheral; + int ret; + int function_id; + int pde_entity; + int port_num; + u8 sample_rate_idx =3D 0; + + if (!tac_dev->hw_init) { + dev_err(tac_dev->dev, + "error: operation without hw initialization"); + return -EINVAL; + } + + sdw_stream =3D snd_soc_dai_get_dma_data(dai, substream); + if (!sdw_stream) { + dev_err(tac_dev->dev, "failed to get dma data"); + return -EINVAL; + } + + ret =3D tac_clear_latch(tac_dev); + if (ret) + dev_warn(tac_dev->dev, "clear latch failed, err=3D%d", ret); + + switch (dai->id) { + case TAC5XX2_DMIC: + function_id =3D TAC_FUNCTION_ID_SM; + pde_entity =3D TAC_SDCA_ENT_PDE11; + port_num =3D TAC_SDW_PORT_NUM_DMIC; + break; + case TAC5XX2_UAJ: + function_id =3D TAC_FUNCTION_ID_UAJ; + pde_entity =3D substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK ? + TAC_SDCA_ENT_PDE47 : TAC_SDCA_ENT_PDE34; + port_num =3D substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK ? + TAC_SDW_PORT_NUM_UAJ_PLAYBACK : + TAC_SDW_PORT_NUM_UAJ_CAPTURE; + break; + case TAC5XX2_SPK: + function_id =3D TAC_FUNCTION_ID_SA; + pde_entity =3D TAC_SDCA_ENT_PDE23; + port_num =3D substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK ? + TAC_SDW_PORT_NUM_SPK_PLAYBACK : + TAC_SDW_PORT_NUM_SPK_CAPTURE; + break; + default: + dev_err(tac_dev->dev, "Invalid dai id: %d for power up\n", dai->id); + return -EINVAL; + } + + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); + port_config.num =3D port_num; + ret =3D sdw_stream_add_slave(sdw_peripheral, &stream_config, + &port_config, 1, sdw_stream); + if (ret) { + dev_err(dai->dev, + "Unable to configure port %d: %d\n", port_num, ret); + return ret; + } + + switch (params_rate(params)) { + case 48000: + sample_rate_idx =3D 0x01; + break; + case 44100: + sample_rate_idx =3D 0x02; + break; + case 96000: + sample_rate_idx =3D 0x03; + break; + case 88200: + sample_rate_idx =3D 0x04; + break; + default: + dev_dbg(tac_dev->dev, "Unsupported sample rate: %d Hz", + params_rate(params)); + return -EINVAL; + } + + switch (function_id) { + case TAC_FUNCTION_ID_SM: + ret =3D regmap_write(tac_dev->regmap, + SDW_SDCA_CTL(function_id, TAC_SDCA_ENT_CS113, + TAC_SDCA_CTL_CS_SAMP_RATE_IDX, 0), + sample_rate_idx); + if (ret) { + dev_err(tac_dev->dev, "Failed to set CS113 sample rate: %d", ret); + return ret; + } + + break; + case TAC_FUNCTION_ID_UAJ: + if (substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK) { + ret =3D regmap_write(tac_dev->regmap, + SDW_SDCA_CTL(function_id, TAC_SDCA_ENT_CS41, + TAC_SDCA_CTL_CS_SAMP_RATE_IDX, 0), + sample_rate_idx); + if (ret) { + dev_err(tac_dev->dev, "Failed to set CS41 sample rate: %d", ret); + return ret; + } + } else { + ret =3D regmap_write(tac_dev->regmap, + SDW_SDCA_CTL(function_id, TAC_SDCA_ENT_CS36, + TAC_SDCA_CTL_CS_SAMP_RATE_IDX, 0), + sample_rate_idx); + if (ret) { + dev_err(tac_dev->dev, "Failed to set CS36 sample rate: %d", ret); + return ret; + } + } + break; + case TAC_FUNCTION_ID_SA: + /* SmartAmp: no additional sample rate configuration needed */ + break; + } + + ret =3D regmap_write(tac_dev->regmap, SDW_SDCA_CTL(function_id, pde_entit= y, + TAC_SDCA_REQUESTED_PS, 0), 0); + if (ret) { + dev_err(tac_dev->dev, + "failed to set func %d, entity %d's requested PS to 0: %d\n", + function_id, pde_entity, ret); + return ret; + } + + ret =3D sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, funct= ion_id, pde_entity, + SDCA_PDE_PS3, SDCA_PDE_PS0, NULL, 0); + if (ret) + dev_err(tac_dev->dev, "failed to transition func %d, pde %d from PS3 -> = PS0, err=3D%d\n", + function_id, pde_entity, ret); + return ret; +} + +static int tac_sdw_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_runtime *sdw_stream =3D snd_soc_dai_get_dma_data(dai, s= ubstream); + struct tac5xx2_prv *tac_dev =3D snd_soc_component_get_drvdata(dai->compon= ent); + int pde_entity, function_id; + int ret; + + sdw_stream_remove_slave(tac_dev->sdw_peripheral, sdw_stream); + + switch (dai->id) { + case TAC5XX2_DMIC: + pde_entity =3D TAC_SDCA_ENT_PDE11; + function_id =3D TAC_FUNCTION_ID_SM; + break; + case TAC5XX2_UAJ: + function_id =3D TAC_FUNCTION_ID_UAJ; + pde_entity =3D substream->stream =3D=3D SNDRV_PCM_STREAM_PLAYBACK ? + TAC_SDCA_ENT_PDE47 : TAC_SDCA_ENT_PDE34; + break; + case TAC5XX2_SPK: + function_id =3D TAC_FUNCTION_ID_SA; + pde_entity =3D TAC_SDCA_ENT_PDE23; + break; + default: + dev_err(tac_dev->dev, "unhandled dai %d for power down\n", dai->id); + return -EINVAL; + } + + ret =3D regmap_write(tac_dev->regmap, SDW_SDCA_CTL(function_id, pde_entit= y, + TAC_SDCA_REQUESTED_PS, 0), + SDCA_PDE_PS3); + if (ret) { + dev_err(tac_dev->dev, + "failed to set func %d, entity %d's requested PS to 3: %d\n", + function_id, pde_entity, ret); + return ret; + } + + ret =3D sdca_asoc_pde_poll_actual_ps(tac_dev->dev, tac_dev->regmap, funct= ion_id, + pde_entity, SDCA_PDE_PS0, SDCA_PDE_PS3, + NULL, 0); + if (ret) + dev_err(tac_dev->dev, + "failed to transition func %d, pde %d from PS0 -> PS3, err=3D%d\n", + function_id, pde_entity, ret); + + return ret; +} + +static const struct snd_soc_dai_ops tac_dai_ops =3D { + .hw_params =3D tac_sdw_hw_params, + .hw_free =3D tac_sdw_pcm_hw_free, + .set_stream =3D tac_set_sdw_stream, + .shutdown =3D tac_sdw_shutdown, +}; + +static int tac5xx2_sdca_btn_type(unsigned char *buffer, struct tac5xx2_prv= *tac_dev) +{ + switch (*buffer) { + case 1: /* play pause */ + return SND_JACK_BTN_0; + case 10: /* vol down */ + return SND_JACK_BTN_3; + case 8: /* vol up */ + return SND_JACK_BTN_2; + case 4: /* long press */ + return SND_JACK_BTN_1; + case 2: /* next song */ + case 32: /* next song */ + return SND_JACK_BTN_4; + default: + return 0; + } +} + +static int tac5xx2_sdca_button_detect(struct tac5xx2_prv *tac_dev) +{ + unsigned int btn_type, offset, idx; + int ret, value, owner; + u8 buf[2]; + + ret =3D regmap_read(tac_dev->regmap, + SDW_SDCA_CTL(TAC_FUNCTION_ID_HID, TAC_SDCA_ENT_HID1, + TAC_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), &owner); + if (ret) { + dev_err(tac_dev->dev, + "Failed to read current UMP message owner 0x%x", ret); + return ret; + } + + if (owner =3D=3D SDCA_UMP_OWNER_DEVICE) { + dev_dbg(tac_dev->dev, "skip button detect as current owner is not host\n= "); + return 0; + } + + ret =3D regmap_read(tac_dev->regmap, + SDW_SDCA_CTL(TAC_FUNCTION_ID_HID, TAC_SDCA_ENT_HID1, + TAC_SDCA_CTL_HIDTX_MESSAGE_OFFSET, 0), &offset); + if (ret) { + dev_err(tac_dev->dev, + "Failed to read current UMP message offset: %d", ret); + goto end_btn_det; + } + + dev_dbg(tac_dev->dev, "button detect: message offset =3D %x", offset); + + for (idx =3D 0; idx < sizeof(buf); idx++) { + ret =3D regmap_read(tac_dev->regmap, + TAC_BUF_ADDR_HID1 + offset + idx, &value); + if (ret) { + dev_err(tac_dev->dev, + "Failed to read HID buffer: %d", ret); + goto end_btn_det; + } + buf[idx] =3D value & 0xff; + } + + if (buf[0] =3D=3D 0x1) { + btn_type =3D tac5xx2_sdca_btn_type(&buf[1], tac_dev); + ret =3D btn_type; + } + +end_btn_det: + regmap_write(tac_dev->regmap, + SDW_SDCA_CTL(TAC_FUNCTION_ID_HID, TAC_SDCA_ENT_HID1, + TAC_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01); + + return ret; +} + +static int tac5xx2_sdca_headset_detect(struct tac5xx2_prv *tac_dev) +{ + int val, ret; + + ret =3D regmap_read(tac_dev->regmap, + SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35, + TAC_SDCA_CTL_DET_MODE, 0), &val); + if (ret) { + dev_err(tac_dev->dev, "Failed to read the detect mode"); + return ret; + } + + switch (val) { + case 4: + tac_dev->jack_type =3D SND_JACK_MICROPHONE; + break; + case 5: + tac_dev->jack_type =3D SND_JACK_HEADPHONE; + break; + case 6: + tac_dev->jack_type =3D SND_JACK_HEADSET; + break; + case 0: + default: + tac_dev->jack_type =3D 0; + break; + } + + ret =3D regmap_write(tac_dev->regmap, + SDW_SDCA_CTL(TAC_FUNCTION_ID_UAJ, TAC_SDCA_ENT_GE35, + TAC_SDCA_CTL_SEL_MODE, 0), val); + if (ret) + dev_err(tac_dev->dev, "Failed to update the jack type to device"); + + return 0; +} + +static int tac5xx2_jack_init(struct tac5xx2_prv *tac_dev) +{ + int ret =3D 0; + + if (!tac_dev->hs_jack) + goto disable_interrupts; + + ret =3D regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, + SDW_SCP_SDCA_INTMASK_SDCA_11); + if (ret) { + dev_err(tac_dev->dev, + "Failed to register jack detection interrupt: %d\n", ret); + goto disable_interrupts; + } + + ret =3D regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, + SDW_SCP_SDCA_INTMASK_SDCA_16); + if (ret) { + dev_err(tac_dev->dev, + "Failed to register for button detect interrupt: %d\n", ret); + goto disable_interrupts; + } + + return 0; + +disable_interrupts: + /* ignore errors while disabling interrupts */ + regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK2, 0); + regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INTMASK3, 0); + + return ret; +} + +static int tac5xx2_set_jack(struct snd_soc_component *component, + struct snd_soc_jack *hs_jack, void *data) +{ + struct tac5xx2_prv *tac_dev =3D snd_soc_component_get_drvdata(component); + int ret; + + tac_dev->hs_jack =3D hs_jack; + + /* resume can happen only after first hw_init */ + if (!tac_dev->first_hw_init_done) + return 0; + + ret =3D pm_runtime_resume_and_get(component->dev); + if (ret < 0) { + if (ret !=3D -EACCES) { + dev_err(component->dev, + "%s: failed to resume %d\n", __func__, ret); + return ret; + } + + /* pm_runtime not enabled yet */ + dev_dbg(component->dev, + "%s: skipping jack init for now\n", __func__); + return 0; + } + + ret =3D tac5xx2_jack_init(tac_dev); + if (ret) + dev_err(tac_dev->dev, "jack init failed, err=3D%d\n", ret); + + pm_runtime_mark_last_busy(component->dev); + pm_runtime_put_autosuspend(component->dev); + + return ret; +} + +static int tac_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + struct tac5xx2_prv *tac_dev =3D dev_get_drvdata(&slave->dev); + struct device *dev =3D &slave->dev; + int ret =3D 0; + int btn_type =3D 0; + unsigned int sdca_int2, sdca_int3, jack_report_mask =3D 0; + + if (status->control_port) { + if (status->control_port & SDW_SCP_INT1_PARITY) + dev_warn(dev, "SCP: Parity error interrupt"); + if (status->control_port & SDW_SCP_INT1_BUS_CLASH) + dev_warn(dev, "SCP: Bus clash interrupt"); + } + + ret =3D regmap_read(tac_dev->regmap, SDW_SCP_SDCA_INT2, &sdca_int2); + if (ret) { + dev_err(dev, "Failed to read UAJ Interrupt, reg:%#x err=3D%d\n", + SDW_SCP_SDCA_INT2, ret); + return ret; + } + + ret =3D regmap_read(tac_dev->regmap, SDW_SCP_SDCA_INT3, &sdca_int3); + if (ret) { + dev_err(dev, "Failed to read HID interrupt reg=3D%#x: err=3D%d", + SDW_SCP_SDCA_INT3, ret); + return ret; + } + + dev_dbg(dev, "SDCA_INT2: 0x%02x, SDCA_INT3: 0x%02x\n", + sdca_int2, sdca_int3); + + if (sdca_int2 & SDW_SCP_SDCA_INT_SDCA_11) { + ret =3D tac5xx2_sdca_headset_detect(tac_dev); + if (ret < 0) + goto clear; + jack_report_mask |=3D SND_JACK_HEADSET; + } + + if (sdca_int3 & SDW_SCP_SDCA_INT_SDCA_16) { + btn_type =3D tac5xx2_sdca_button_detect(tac_dev); + if (btn_type < 0) + btn_type =3D 0; + jack_report_mask |=3D SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_BTN_4; + } + + if (tac_dev->jack_type =3D=3D 0) + btn_type =3D 0; + + dev_dbg(tac_dev->dev, "in %s, jack_type=3D%d\n", __func__, tac_dev->jack_= type); + dev_dbg(tac_dev->dev, "in %s, btn_type=3D0x%x\n", __func__, btn_type); + + if (!tac_dev->hs_jack) + goto clear; + + snd_soc_jack_report(tac_dev->hs_jack, tac_dev->jack_type | btn_type, + jack_report_mask); + +clear: + if (sdca_int2) { + ret =3D regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INT2, sdca_int2); + if (ret) + dev_dbg(tac_dev->dev, "Failed to clear jack interrupt\n"); + } + + if (sdca_int3) { + ret =3D regmap_write(tac_dev->regmap, SDW_SCP_SDCA_INT3, sdca_int3); + if (ret) + dev_dbg(tac_dev->dev, "failed to clear hid interrupt\n"); + } + + return 0; +} + +static struct snd_soc_dai_driver tac5572_dai_driver[] =3D { + { + .name =3D "tac5xx2-aif1", + .id =3D TAC5XX2_SPK, + .playback =3D { + .stream_name =3D "DP1 Speaker Playback", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, + { + .name =3D "tac5xx2-aif2", + .id =3D TAC5XX2_DMIC, + .capture =3D { + .stream_name =3D "DP3 Mic Capture", + .channels_min =3D 1, + .channels_max =3D 4, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, + { + .name =3D "tac5xx2-aif3", + .id =3D TAC5XX2_UAJ, + .playback =3D { + .stream_name =3D "DP4 UAJ Speaker Playback", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .capture =3D { + .stream_name =3D "DP7 UAJ Mic Capture", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, +}; + +static struct snd_soc_dai_driver tac5672_dai_driver[] =3D { + { + .name =3D "tac5xx2-aif1", + .id =3D TAC5XX2_SPK, + .playback =3D { + .stream_name =3D "DP1 Speaker Playback", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .capture =3D { + .stream_name =3D "DP8 IV Sense Capture", + .channels_min =3D 1, + .channels_max =3D 4, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + .symmetric_rate =3D 1, + }, + { + .name =3D "tac5xx2-aif2", + .id =3D TAC5XX2_DMIC, + .capture =3D { + .stream_name =3D "DP3 Mic Capture", + .channels_min =3D 1, + .channels_max =3D 4, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, + { + .name =3D "tac5xx2-aif3", + .id =3D TAC5XX2_UAJ, + .playback =3D { + .stream_name =3D "DP4 UAJ Speaker Playback", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .capture =3D { + .stream_name =3D "DP7 UAJ Mic Capture", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, +}; + +static struct snd_soc_dai_driver tac5682_dai_driver[] =3D { + { + .name =3D "tac5xx2-aif1", + .id =3D TAC5XX2_SPK, + .playback =3D { + .stream_name =3D "DP1 Speaker Playback", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .capture =3D { + .stream_name =3D "DP2 Echo Reference Capture", + .channels_min =3D 1, + .channels_max =3D 4, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + .symmetric_rate =3D 1, + }, + { + .name =3D "tac5xx2-aif2", + .id =3D TAC5XX2_DMIC, + .capture =3D { + .stream_name =3D "DP3 Mic Capture", + .channels_min =3D 1, + .channels_max =3D 4, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, + { + .name =3D "tac5xx2-aif3", + .id =3D TAC5XX2_UAJ, + .playback =3D { + .stream_name =3D "DP4 UAJ Speaker Playback", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .capture =3D { + .stream_name =3D "DP7 UAJ Mic Capture", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, +}; + +static struct snd_soc_dai_driver tas2883_dai_driver[] =3D { + { + .name =3D "tac5xx2-aif1", + .id =3D TAC5XX2_SPK, + .playback =3D { + .stream_name =3D "DP1 Speaker Playback", + .channels_min =3D 1, + .channels_max =3D 2, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + .symmetric_rate =3D 1, + }, + { + .name =3D "tac5xx2-aif2", + .id =3D TAC5XX2_DMIC, + .capture =3D { + .stream_name =3D "DP3 Mic Capture", + .channels_min =3D 1, + .channels_max =3D 4, + .rates =3D TAC5XX2_DEVICE_RATES, + .formats =3D TAC5XX2_DEVICE_FORMATS, + }, + .ops =3D &tac_dai_ops, + }, +}; + +static s32 tac_component_probe(struct snd_soc_component *component) +{ + struct tac5xx2_prv *tac_dev =3D + snd_soc_component_get_drvdata(component); + struct device *dev =3D tac_dev->dev; + struct sdw_slave *slave =3D tac_dev->sdw_peripheral; + unsigned long time; + int ret; + + /* Wait for SoundWire hw initialization to complete */ + time =3D wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(TAC5XX2_PROBE_TIMEOUT_MS)); + if (!time) { + dev_warn(dev, "%s: hw initialization timeout\n", __func__); + return -ETIMEDOUT; + } + + if (!tac_has_uaj_support(tac_dev)) + goto done_comp_probe; + + ret =3D snd_soc_dapm_new_controls(snd_soc_component_to_dapm(component), + tac_uaj_widgets, + ARRAY_SIZE(tac_uaj_widgets)); + if (ret) { + dev_err(component->dev, "Failed to add UAJ widgets: %d\n", ret); + return ret; + } + + ret =3D snd_soc_dapm_add_routes(snd_soc_component_to_dapm(component), + tac_uaj_routes, ARRAY_SIZE(tac_uaj_routes)); + if (ret) { + dev_err(component->dev, "Failed to add UAJ routes: %d\n", ret); + return ret; + } + + ret =3D snd_soc_add_component_controls(component, tac_uaj_controls, + ARRAY_SIZE(tac_uaj_controls)); + if (ret) { + dev_err(dev, "Failed to add UAJ controls: %d\n", ret); + return ret; + } + +done_comp_probe: + tac_dev->component =3D component; + return 0; +} + +static void tac_component_remove(struct snd_soc_component *codec) +{ + struct tac5xx2_prv *tac_dev =3D snd_soc_component_get_drvdata(codec); + + tac_dev->component =3D NULL; +} + +static const struct snd_soc_component_driver soc_codec_driver_tacdevice = =3D { + .probe =3D tac_component_probe, + .remove =3D tac_component_remove, + .controls =3D tac5xx2_snd_controls, + .num_controls =3D ARRAY_SIZE(tac5xx2_snd_controls), + .dapm_widgets =3D tac5xx2_common_widgets, + .num_dapm_widgets =3D ARRAY_SIZE(tac5xx2_common_widgets), + .dapm_routes =3D tac5xx2_common_routes, + .num_dapm_routes =3D ARRAY_SIZE(tac5xx2_common_routes), + .idle_bias_on =3D 0, + .endianness =3D 1, +}; + +static s32 tac_init(struct tac5xx2_prv *tac_dev) +{ + s32 ret; + struct snd_soc_dai_driver *dai_drv; + struct snd_soc_component_driver *component_driver; + int num_dais; + + dev_set_drvdata(tac_dev->dev, tac_dev); + + switch (tac_dev->part_id) { + case 0x5572: + dai_drv =3D tac5572_dai_driver; + num_dais =3D ARRAY_SIZE(tac5572_dai_driver); + break; + case 0x5672: + dai_drv =3D tac5672_dai_driver; + num_dais =3D ARRAY_SIZE(tac5672_dai_driver); + break; + case 0x5682: + dai_drv =3D tac5682_dai_driver; + num_dais =3D ARRAY_SIZE(tac5682_dai_driver); + break; + case 0x2883: + dai_drv =3D tas2883_dai_driver; + num_dais =3D ARRAY_SIZE(tas2883_dai_driver); + break; + default: + dev_err(tac_dev->dev, "Unsupported device: 0x%x\n", + tac_dev->part_id); + return -EINVAL; + } + + component_driver =3D devm_kzalloc(tac_dev->dev, sizeof(*component_driver), + GFP_KERNEL); + if (!component_driver) + return -ENOMEM; + + memcpy(component_driver, &soc_codec_driver_tacdevice, sizeof(*component_d= river)); + if (tac_has_uaj_support(tac_dev)) + component_driver->set_jack =3D tac5xx2_set_jack; + + ret =3D devm_snd_soc_register_component(tac_dev->dev, component_driver, + dai_drv, num_dais); + if (ret) { + dev_err(tac_dev->dev, "%s: codec register error:%d.\n", + __func__, ret); + return ret; + } + + return 0; +} + +static s32 tac5xx2_sdca_dev_suspend(struct device *dev) +{ + struct tac5xx2_prv *tac_dev =3D dev_get_drvdata(dev); + + if (!tac_dev->hw_init) + return 0; + + regcache_cache_only(tac_dev->regmap, true); + return 0; +} + +static s32 tac5xx2_sdca_dev_system_suspend(struct device *dev) +{ + return tac5xx2_sdca_dev_suspend(dev); +} + +static s32 tac5xx2_sdca_dev_resume(struct device *dev) +{ + struct sdw_slave *slave =3D dev_to_sdw_dev(dev); + struct tac5xx2_prv *tac_dev =3D dev_get_drvdata(dev); + unsigned long t; + int ret; + bool had_unattached =3D false; + + if (!tac_dev->first_hw_init_done) { + dev_dbg(dev, "Device not initialized yet, skipping resume sync\n"); + return 0; + } + + if (!slave->unattach_request) + goto regmap_sync; + + had_unattached =3D true; + t =3D wait_for_completion_timeout(&slave->initialization_complete, + msecs_to_jiffies(TAC5XX2_PROBE_TIMEOUT_MS)); + if (!t) { + dev_err(&slave->dev, "resume: initialization timed out\n"); + sdw_show_ping_status(slave->bus, true); + return -ETIMEDOUT; + } + slave->unattach_request =3D 0; + + /* Detect and set jack type for UAJ path before playback. + * This is required as jack detection does not trigger interrupt + * when device is in runtime_pm suspend with bus in clock stop mode. + */ + tac5xx2_sdca_headset_detect(tac_dev); + +regmap_sync: + regcache_cache_only(tac_dev->regmap, false); + if (!had_unattached) { + regcache_mark_dirty(tac_dev->regmap); + ret =3D regcache_sync(tac_dev->regmap); + if (ret < 0) + dev_warn(dev, "Failed to sync regcache: %d\n", ret); + } + + return 0; +} + +static const struct dev_pm_ops tac5xx2_sdca_pm =3D { + SYSTEM_SLEEP_PM_OPS(tac5xx2_sdca_dev_system_suspend, tac5xx2_sdca_dev_res= ume) + RUNTIME_PM_OPS(tac5xx2_sdca_dev_suspend, tac5xx2_sdca_dev_resume, NULL) +}; + +static s32 tac_fw_read_hdr(const u8 *data, struct tac_fw_hdr *hdr) +{ + hdr->size =3D get_unaligned_le32(data); + hdr->version_offset =3D get_unaligned_le32(data + 4); + hdr->plt_id =3D get_unaligned_le32(data + 8); + hdr->ppc3_ver =3D get_unaligned_le32(data + 12); + memcpy(hdr->ddc_name, data + 16, 64); + hdr->ddc_name[63] =3D 0; + hdr->timestamp =3D get_unaligned_le64(data + 80); + + return TAC_FW_HDR_SIZE; +} + +static s32 tac_fw_get_next_file(const u8 *data, size_t data_size, struct t= ac_fw_file *file) +{ + u32 file_length; + + /* Validate file header size */ + if (data_size < TAC_FW_FILE_HDR) + return -EINVAL; + + file->vendor_id =3D get_unaligned_le32(&data[0]); + file->file_id =3D get_unaligned_le32(&data[4]); + file->version =3D get_unaligned_le32(&data[8]); + file->length =3D get_unaligned_le32(&data[12]); + file->dest_addr =3D get_unaligned_le32(&data[16]); + file_length =3D file->length; + + /* Validate file payload exists */ + if (data_size < TAC_FW_FILE_HDR + file_length) + return -EINVAL; + + file->fw_data =3D (u8 *)&data[20]; + + return file_length + sizeof(u32) * 5; +} + +static void tac5xx2_fw_ready(const struct firmware *fmw, void *context) +{ + s32 ret =3D 0; + u32 fw_hdr_size; + size_t img_sz; + u32 offset; + u32 num_files =3D 0; + struct tm tm_time; + struct tac_fw_hdr hdr; + struct tac_fw_file *files; + u8 *buf; + struct tac5xx2_prv *tac_dev =3D context; + + if (!fmw || !fmw->data || fmw->size =3D=3D 0 || fmw->size < TAC_FW_HDR_SI= ZE + TAC_FW_FILE_HDR) { + dev_err(tac_dev->dev, "fw file: %s is empty or invalid\n", + tac_dev->fw_binaryname); + goto out; + } + + /* Verify firmware size from header */ + fw_hdr_size =3D get_unaligned_le32(fmw->data); + if (fw_hdr_size !=3D fmw->size) { + dev_err(tac_dev->dev, "firmware size mismatch: hdr=3D%u, actual=3D%zu\n", + fw_hdr_size, fmw->size); + goto out; + } + + files =3D devm_kzalloc(tac_dev->dev, sizeof(*files) * TAC_MAX_FW_CHUNKS, = GFP_KERNEL); + buf =3D devm_kmemdup(tac_dev->dev, fmw->data, fmw->size, GFP_KERNEL); + if (!files || !buf) + goto out; + + /* validate the cache the firmware */ + img_sz =3D fmw->size; + offset =3D tac_fw_read_hdr(buf, &hdr); + while (offset < img_sz && num_files < TAC_MAX_FW_CHUNKS) { + u32 file_length; + + if (offset + TAC_FW_FILE_HDR > img_sz) { + dev_warn(tac_dev->dev, "Incomplete block header at offset %d\n", + offset); + goto out; + } + /* Validate that the file payload doesn't exceed buffer */ + file_length =3D get_unaligned_le32(&buf[offset + 12]); + /* Check for integer overflow and buffer bounds */ + if (file_length > img_sz || offset > img_sz - TAC_FW_FILE_HDR || + file_length > img_sz - offset - TAC_FW_FILE_HDR) { + dev_warn(tac_dev->dev, "File at offset %d exceeds buffer: length=3D%u, = available=3D%zu\n", + offset, file_length, img_sz - offset - TAC_FW_FILE_HDR); + goto out; + } + ret =3D tac_fw_get_next_file(&buf[offset], img_sz - offset, &files[num_f= iles]); + if (ret < 0) { + dev_err(tac_dev->dev, "Failed to parse file at offset %d\n", offset); + goto out; + } + offset +=3D ret; + num_files++; + } + + if (num_files =3D=3D 0) { + dev_err(tac_dev->dev, "firmware with no files\n"); + goto out; + } + + /* cache ready to use validated firmware */ + tac_dev->fw_file_cnt =3D num_files; + tac_dev->fw_files =3D files; + + time64_to_tm(hdr.timestamp, 0, &tm_time); + dev_dbg(tac_dev->dev, "fw file: %s, num_files=3D%u, ts:%04ld-%02d-%02d %0= 2d:%02d\n", + tac_dev->fw_binaryname, tac_dev->fw_file_cnt, + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min); + dev_dbg(tac_dev->dev, "fw file: DDC Name: %s\n", hdr.ddc_name); + dev_dbg(tac_dev->dev, "fw file: PPC3 Version: 3.%ld.%ld.%ld\n", + FIELD_GET(GENMASK(31, 24), hdr.ppc3_ver), + FIELD_GET(GENMASK(23, 16), hdr.ppc3_ver), + FIELD_GET(GENMASK(15, 8), hdr.ppc3_ver) & 0x3f); + +out: + complete_all(&tac_dev->fw_caching_complete); + if (fmw) + release_firmware(fmw); +} + +static int tac_load_and_cache_firmware_async(struct tac5xx2_prv *tac_dev) +{ + tac_dev->fw_file_cnt =3D 0; + tac_dev->fw_files =3D NULL; /* ready to download files */ + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, + tac_dev->fw_binaryname, tac_dev->dev, + GFP_KERNEL, tac_dev, tac5xx2_fw_ready); +} + +static int tac_download(struct tac5xx2_prv *tac_dev) +{ + int ret =3D 0; + u32 i; + struct tac_fw_file *files =3D tac_dev->fw_files; + u32 num_files =3D tac_dev->fw_file_cnt; + + for (i =3D 0; i < num_files; i++) { + ret =3D sdw_nwrite_no_pm(tac_dev->sdw_peripheral, files[i].dest_addr, + files[i].length, files[i].fw_data); + if (ret < 0) { + dev_dbg(tac_dev->dev, + "FW write failed at addr 0x%x: %d\n", + files[i].dest_addr, ret); + return ret; + } + } + + return 0; +} + +/* + * tac5xx2 uses custom firmware binary fw. + * This is not using UMP File Download. + */ +static s32 tac_download_fw_to_hw(struct tac5xx2_prv *tac_dev) +{ + int ret; + + ret =3D tac_download(tac_dev); + if (ret < 0) { + dev_err(tac_dev->dev, "Firmware download failed: %d\n", ret); + return ret; + } + + dev_dbg(tac_dev->dev, "Firmware download complete: %d chunks\n", + tac_dev->fw_file_cnt); + tac_dev->fw_dl_success =3D true; + + return 0; +} + +static struct pci_dev *tac_get_pci_dev(struct sdw_slave *peripheral) +{ + struct device *dev =3D &peripheral->dev; + + for (; dev; dev =3D dev->parent) { + if (dev_is_pci(dev)) + return to_pci_dev(dev); + } + + return NULL; +} + +static void tac_generate_fw_name(struct sdw_slave *slave, char *name, size= _t size) +{ + struct sdw_bus *bus =3D slave->bus; + u16 part_id =3D slave->id.part_id; + u8 unique_id =3D slave->id.unique_id; + struct pci_dev *pci =3D tac_get_pci_dev(slave); + + if (pci) + scnprintf(name, size, "%04X-%04X-%1X-%1X.bin", part_id, + pci->subsystem_device, bus->link_id, unique_id); + else + /* Default firmware name based on part ID */ + scnprintf(name, size, "%s%04x-%1X-%1X.bin", + part_id =3D=3D 0x2883 ? "tas" : "tac", + part_id, bus->link_id, unique_id); +} + +static int tac_io_init(struct device *dev, struct sdw_slave *slave, bool f= irst) +{ + int ret; + u64 time; + struct tac5xx2_prv *tac_dev =3D dev_get_drvdata(dev); + + if (tac_dev->hw_init) { + dev_dbg(dev, "early return hw_init already done.."); + return 0; + } + + time =3D wait_for_completion_timeout(&tac_dev->fw_caching_complete, + msecs_to_jiffies(TAC5XX2_FW_CACHE_TIMEOUT_MS)); + if (!time) { + ret =3D -ETIMEDOUT; + dev_warn(tac_dev->dev, "%s: fw caching timeout\n", __func__); + goto io_init_err; + } + + if (tac_dev->fw_files && tac_dev->fw_file_cnt > 0) { + ret =3D tac_download_fw_to_hw(tac_dev); + if (ret) { + dev_err(tac_dev->dev, "FW download failed, fw: %d\n", ret); + goto io_init_err; + } + } + + if (tac_dev->sa_func_data) { + ret =3D sdca_regmap_write_init(dev, tac_dev->regmap, + tac_dev->sa_func_data); + if (ret) { + dev_err(dev, "smartamp init table update failed\n"); + goto io_init_err; + } + dev_dbg(dev, "smartamp init done\n"); + + if (first) { + ret =3D regmap_multi_reg_write(tac_dev->regmap, tac_spk_seq, + ARRAY_SIZE(tac_spk_seq)); + if (ret) { + dev_err(dev, "init writes failed, err=3D%d", ret); + goto io_init_err; + } + } + } + + if (tac_dev->sm_func_data) { + ret =3D sdca_regmap_write_init(dev, tac_dev->regmap, + tac_dev->sm_func_data); + if (ret) { + dev_err(dev, "smartmic init table update failed\n"); + goto io_init_err; + } + dev_dbg(dev, "smartmic init done\n"); + + if (first) { + ret =3D regmap_multi_reg_write(tac_dev->regmap, tac_sm_seq, + ARRAY_SIZE(tac_sm_seq)); + if (ret) { + dev_err(tac_dev->dev, + "init writes failed, err=3D%d", ret); + goto io_init_err; + } + } + } + + if (tac_dev->uaj_func_data) { + ret =3D sdca_regmap_write_init(dev, tac_dev->regmap, + tac_dev->uaj_func_data); + if (ret) { + dev_err(dev, "uaj init table update failed\n"); + goto io_init_err; + } + dev_dbg(dev, "uaj init done\n"); + + if (first) { + ret =3D regmap_multi_reg_write(tac_dev->regmap, tac_uaj_seq, + ARRAY_SIZE(tac_uaj_seq)); + if (ret) { + dev_err(tac_dev->dev, + "init writes failed, err=3D%d", ret); + goto io_init_err; + } + + if (tac_dev->hs_jack) { + ret =3D tac5xx2_jack_init(tac_dev); + if (ret) { + dev_err(tac_dev->dev, "jack init failed"); + goto io_init_err; + } + } + } + } + + if (tac_dev->hid_func_data) { + ret =3D sdca_regmap_write_init(dev, tac_dev->regmap, + tac_dev->hid_func_data); + if (ret) { + dev_err(dev, "hid init table update failed\n"); + goto io_init_err; + } + dev_dbg(dev, "hid init done\n"); + } + + tac_dev->hw_init =3D true; + + return 0; + +io_init_err: + dev_err(dev, "init writes failed, err=3D%d", ret); + return ret; +} + +static int tac_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + int ret; + bool first =3D false; + struct tac5xx2_prv *tac_dev =3D dev_get_drvdata(&slave->dev); + struct device *dev =3D &slave->dev; + + tac_dev->status =3D status; + if (status =3D=3D SDW_SLAVE_UNATTACHED) { + tac_dev->hw_init =3D false; + tac_dev->fw_dl_success =3D false; + } + + if (tac_dev->hw_init || tac_dev->status !=3D SDW_SLAVE_ATTACHED) { + dev_dbg(dev, "%s: early return, hw_init=3D%d, status=3D%d", + __func__, tac_dev->hw_init, tac_dev->status); + return 0; + } + + if (!tac_dev->first_hw_init_done) { + pm_runtime_set_active(tac_dev->dev); + tac_dev->first_hw_init_done =3D true; + first =3D true; + } + + pm_runtime_get_noresume(tac_dev->dev); + + regcache_mark_dirty(tac_dev->regmap); + regcache_cache_only(tac_dev->regmap, false); + ret =3D tac_io_init(&slave->dev, slave, first); + if (ret) { + dev_err(dev, "Device initialization failed: %d\n", ret); + goto err_out; + } + + ret =3D regcache_sync(tac_dev->regmap); + if (ret) + dev_warn(dev, "Failed to sync regcache after init: %d\n", ret); + +err_out: + pm_runtime_mark_last_busy(tac_dev->dev); + pm_runtime_put_autosuspend(tac_dev->dev); + + return ret; +} + +static int tac5xx2_sdw_read_prop(struct sdw_slave *peripheral) +{ + struct device *dev =3D &peripheral->dev; + int ret; + + ret =3D sdw_slave_read_prop(peripheral); + if (ret) { + dev_err(dev, "sdw_slave_read_prop failed: %d", ret); + return ret; + } + + return 0; +} + +static int tac_port_prep(struct sdw_slave *slave, struct sdw_prepare_ch *p= rep_ch, + enum sdw_port_prep_ops pre_ops) +{ + struct device *dev =3D &slave->dev; + struct tac5xx2_prv *tac_dev =3D dev_get_drvdata(dev); + unsigned int val; + int ret; + + if (pre_ops !=3D SDW_OPS_PORT_POST_PREP) + return 0; + + if (!tac_dev->fw_dl_success) + return 0; + + ret =3D regmap_read(tac_dev->regmap, TAC_DSP_ALGO_STATUS, &val); + if (ret) { + dev_err(dev, "Failed to read algo status: %d\n", ret); + return ret; + } + + if (val !=3D TAC_DSP_ALGO_STATUS_RUNNING) { + dev_dbg(dev, "Algo not running (0x%02x), re-enabling\n", val); + ret =3D regmap_write(tac_dev->regmap, TAC_DSP_ALGO_STATUS, + TAC_DSP_ALGO_STATUS_RUNNING); + if (ret) { + dev_err(dev, "Failed to re-enable algo: %d\n", ret); + return ret; + } + } + + return 0; +} + +static const struct sdw_slave_ops tac_sdw_ops =3D { + .read_prop =3D tac5xx2_sdw_read_prop, + .update_status =3D tac_update_status, + .interrupt_callback =3D tac_interrupt_callback, + .port_prep =3D tac_port_prep, +}; + +static s32 tac_sdw_probe(struct sdw_slave *peripheral, + const struct sdw_device_id *id) +{ + struct regmap *regmap; + struct device *dev =3D &peripheral->dev; + struct tac5xx2_prv *tac_dev; + struct sdca_function_data *function_data =3D NULL; + int ret, i; + + tac_dev =3D devm_kzalloc(dev, sizeof(*tac_dev), GFP_KERNEL); + if (!tac_dev) + return dev_err_probe(dev, -ENOMEM, + "Failed devm_kzalloc"); + + if (peripheral->sdca_data.num_functions > 0) { + dev_dbg(dev, "SDCA functions found: %d", + peripheral->sdca_data.num_functions); + + for (i =3D 0; i < peripheral->sdca_data.num_functions; i++) { + struct sdca_function_data **func_ptr; + const char *func_name; + + switch (peripheral->sdca_data.function[i].type) { + case SDCA_FUNCTION_TYPE_SMART_AMP: + func_ptr =3D &tac_dev->sa_func_data; + func_name =3D "smartamp"; + break; + case SDCA_FUNCTION_TYPE_SMART_MIC: + func_ptr =3D &tac_dev->sm_func_data; + func_name =3D "smartmic"; + break; + case SDCA_FUNCTION_TYPE_UAJ: + func_ptr =3D &tac_dev->uaj_func_data; + func_name =3D "uaj"; + break; + case SDCA_FUNCTION_TYPE_HID: + func_ptr =3D &tac_dev->hid_func_data; + func_name =3D "hid"; + break; + default: + continue; + } + + function_data =3D devm_kzalloc(dev, sizeof(*function_data), + GFP_KERNEL); + if (!function_data) + return dev_err_probe(dev, -ENOMEM, + "failed to allocate %s function data", + func_name); + + ret =3D sdca_parse_function(dev, peripheral, + &peripheral->sdca_data.function[i], + function_data); + if (!ret) + *func_ptr =3D function_data; + else + devm_kfree(dev, function_data); + } + } + + dev_dbg(dev, "SDCA functions enabled: SA=3D%s SM=3D%s UAJ=3D%s HID=3D%s", + tac_dev->sa_func_data ? "yes" : "no", + tac_dev->sm_func_data ? "yes" : "no", + tac_dev->uaj_func_data ? "yes" : "no", + tac_dev->hid_func_data ? "yes" : "no"); + + tac_dev->dev =3D dev; + tac_dev->sdw_peripheral =3D peripheral; + tac_dev->hw_init =3D false; + tac_dev->first_hw_init_done =3D false; + tac_dev->part_id =3D id->part_id; + dev_set_drvdata(dev, tac_dev); + + regmap =3D devm_regmap_init_sdw_mbq_cfg(&peripheral->dev, peripheral, + &tac_regmap, &tac_mbq_cfg); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed devm_regmap_init_sdw\n"); + + regcache_cache_only(regmap, true); + tac_dev->regmap =3D regmap; + tac_dev->jack_type =3D 0; + init_completion(&tac_dev->fw_caching_complete); + + if (tac_has_dsp_algo(tac_dev)) { + tac_generate_fw_name(peripheral, tac_dev->fw_binaryname, + sizeof(tac_dev->fw_binaryname)); + + ret =3D tac_load_and_cache_firmware_async(tac_dev); + if (ret) { + complete_all(&tac_dev->fw_caching_complete); + dev_dbg(dev, "failed to load fw: %d, use rom mode\n", ret); + } + } else { + complete_all(&tac_dev->fw_caching_complete); + } + + ret =3D tac_init(tac_dev); + if (ret) + return dev_err_probe(dev, ret, + "failed to initialize tac device\n"); + + /* set autosuspend parameters */ + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + + /* make sure the device does not suspend immediately */ + pm_runtime_mark_last_busy(dev); + + pm_runtime_enable(dev); + /* the device is still not in active */ + + return 0; +} + +static void tac_sdw_remove(struct sdw_slave *peripheral) +{ + struct tac5xx2_prv *tac_dev =3D dev_get_drvdata(&peripheral->dev); + + pm_runtime_disable(tac_dev->dev); + + dev_set_drvdata(&peripheral->dev, NULL); +} + +static const struct sdw_device_id tac_sdw_id[] =3D { + SDW_SLAVE_ENTRY(0x0102, 0x5572, 0), + SDW_SLAVE_ENTRY(0x0102, 0x5672, 0), + SDW_SLAVE_ENTRY(0x0102, 0x5682, 0), + SDW_SLAVE_ENTRY(0x0102, 0x2883, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, tac_sdw_id); + +static struct sdw_driver tac_sdw_driver =3D { + .driver =3D { + .name =3D "slave-tac5xx2", + .pm =3D pm_ptr(&tac5xx2_sdca_pm), + }, + .probe =3D tac_sdw_probe, + .remove =3D tac_sdw_remove, + .ops =3D &tac_sdw_ops, + .id_table =3D tac_sdw_id, +}; +module_sdw_driver(tac_sdw_driver); + +MODULE_IMPORT_NS("SND_SOC_SDCA"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("ASoC TAC5XX2 SoundWire Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/tac5xx2.h b/sound/soc/codecs/tac5xx2.h new file mode 100644 index 000000000..eed8e6cf3 --- /dev/null +++ b/sound/soc/codecs/tac5xx2.h @@ -0,0 +1,259 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * ALSA SoC Texas Instruments TAC5XX2 Audio Smart Amplifier + * + * Copyright (C) 2025 Texas Instruments Incorporated + * https://www.ti.com + * + * This the header file for TAC5XX2 family of devices + * which includes TAC5572, TAC5672, TAC5682 and TAS2883 + * + * Author: Niranjan H Y + */ +#ifndef __RGL_TAC5XX2_H__ +#define __RGL_TAC5XX2_H__ + +/* for soundwire */ +#define TAC_REG_SDW(book, page, reg) (((book) * 256 * 128) + \ + 0x3000000 + ((page) * 128) + (reg)) + +/* page 0 registers */ +#define TAC_SW_RESET TAC_REG_SDW(0, 0, 1) +#define TAC_SLEEP_MODEZ TAC_REG_SDW(0, 0, 2) +#define TAC_FEATURE_PDZ TAC_REG_SDW(0, 0, 3) +#define TAC_TX_CH_EN TAC_REG_SDW(0, 0, 4) +#define TAC_RX_CH_PD TAC_REG_SDW(0, 0, 5) +#define TAC_SHDNZ_CFG TAC_REG_SDW(0, 0, 6) +#define TAC_MISC_CFG0 TAC_REG_SDW(0, 0, 7) +#define TAC_MISC_CFG1 TAC_REG_SDW(0, 0, 8) +#define TAC_GPIO1_CFG0 TAC_REG_SDW(0, 0, 9) +#define TAC_GPIO2_CFG0 TAC_REG_SDW(0, 0, 10) +#define TAC_GPIO3_CFG0 TAC_REG_SDW(0, 0, 11) +#define TAC_GPIO4_CFG0 TAC_REG_SDW(0, 0, 12) +#define TAC_GPIO5_CFG0 TAC_REG_SDW(0, 0, 13) +#define TAC_GPIO6_CFG0 TAC_REG_SDW(0, 0, 14) +#define TAC_INTF_CFG1 TAC_REG_SDW(0, 0, 15) +#define TAC_INTF_CFG5 TAC_REG_SDW(0, 0, 16) +#define TAC_PASI_BCLK_CFG0 TAC_REG_SDW(0, 0, 17) +#define TAC_PASI_FSYNC_CFG0 TAC_REG_SDW(0, 0, 18) +#define TAC_PASI_DIN1_CFG0 TAC_REG_SDW(0, 0, 19) +#define TAC_PASI_DIN2_CFG0 TAC_REG_SDW(0, 0, 20) +#define TAC_PDM_DIN1_CFG0 TAC_REG_SDW(0, 0, 21) +#define TAC_PDM_DIN2_CFG0 TAC_REG_SDW(0, 0, 22) +#define TAC_MCLK_SEL TAC_REG_SDW(0, 0, 23) +#define TAC_I2C2_CFG0 TAC_REG_SDW(0, 0, 24) +#define TAC_SDW_IO_CFG0 TAC_REG_SDW(0, 0, 25) +#define TAC_SDW_CLK_CFG0 TAC_REG_SDW(0, 0, 26) +#define TAC_PASI_CFG0 TAC_REG_SDW(0, 0, 27) +#define TAC_PASI_CFG1 TAC_REG_SDW(0, 0, 28) +#define TAC_PASI_TX_CFG0 TAC_REG_SDW(0, 0, 29) +#define TAC_PASI_TX_CFG1 TAC_REG_SDW(0, 0, 30) +#define TAC_PASI_TX_CFG2 TAC_REG_SDW(0, 0, 31) +#define TAC_PASI_TX_CFG3 TAC_REG_SDW(0, 0, 32) +#define TAC_PASI_TX_CH1_CFG0 TAC_REG_SDW(0, 0, 33) +#define TAC_PASI_TX_CH2_CFG0 TAC_REG_SDW(0, 0, 34) +#define TAC_PASI_TX_CH3_CFG0 TAC_REG_SDW(0, 0, 35) +#define TAC_PASI_TX_CH4_CFG0 TAC_REG_SDW(0, 0, 36) +#define TAC_PASI_TX_CH5_CFG0 TAC_REG_SDW(0, 0, 37) +#define TAC_PASI_TX_CH6_CFG0 TAC_REG_SDW(0, 0, 38) +#define TAC_PASI_TX_CH7_CFG0 TAC_REG_SDW(0, 0, 39) +#define TAC_PASI_TX_CH8_CFG0 TAC_REG_SDW(0, 0, 40) +#define TAC_PASI_RX_CFG0 TAC_REG_SDW(0, 0, 41) +#define TAC_PASI_RX_CFG1 TAC_REG_SDW(0, 0, 42) +#define TAC_PASI_RX_CFG2 TAC_REG_SDW(0, 0, 43) +#define TAC_PASI_RX_CH1_CFG0 TAC_REG_SDW(0, 0, 44) +#define TAC_PASI_RX_CH2_CFG0 TAC_REG_SDW(0, 0, 45) +#define TAC_PASI_RX_CH3_CFG0 TAC_REG_SDW(0, 0, 46) +#define TAC_PASI_RX_CH4_CFG0 TAC_REG_SDW(0, 0, 47) +#define TAC_PASI_RX_CH5_CFG0 TAC_REG_SDW(0, 0, 48) +#define TAC_PASI_RX_CH6_CFG0 TAC_REG_SDW(0, 0, 49) +#define TAC_PASI_RX_CH7_CFG0 TAC_REG_SDW(0, 0, 50) +#define TAC_PASI_RX_CH8_CFG0 TAC_REG_SDW(0, 0, 51) +#define TAC_ADC_CH1_CFG0 TAC_REG_SDW(0, 0, 52) +#define TAC_ADC_DVOL_CFG0 TAC_REG_SDW(0, 0, 53) +#define TAC_ADC_CH1_FGAIN TAC_REG_SDW(0, 0, 54) +#define TAC_ADC_CH1_CFG1 TAC_REG_SDW(0, 0, 55) +#define TAC_ADC_CH2_CFG0 TAC_REG_SDW(0, 0, 57) +#define TAC_ADC_DVOL_CFG1 TAC_REG_SDW(0, 0, 58) +#define TAC_ADC_CH2_FGAIN TAC_REG_SDW(0, 0, 59) +#define TAC_ADC_CH2_CFG1 TAC_REG_SDW(0, 0, 60) +#define TAC_ADC_CFG1 TAC_REG_SDW(0, 0, 62) +#define TAC_PDM_CH1_DVOL TAC_REG_SDW(0, 0, 63) +#define TAC_PDM_CH1_FGAIN TAC_REG_SDW(0, 0, 64) +#define TAC_PDM_CH1_CFG0 TAC_REG_SDW(0, 0, 65) +#define TAC_PDM_CH2_DVOL TAC_REG_SDW(0, 0, 67) +#define TAC_PDM_CH2_FGAIN TAC_REG_SDW(0, 0, 68) +#define TAC_PDM_CH2_CFG2 TAC_REG_SDW(0, 0, 69) +#define TAC_PDM_CH3_DVOL TAC_REG_SDW(0, 0, 71) +#define TAC_PDM_CH3_FGAIN TAC_REG_SDW(0, 0, 72) +#define TAC_PDM_CH3_CFG0 TAC_REG_SDW(0, 0, 73) +#define TAC_PDM_CH4_DVOL TAC_REG_SDW(0, 0, 75) +#define TAC_PDM_CH4_FGAIN TAC_REG_SDW(0, 0, 76) +#define TAC_PDM_CH4_CFG0 TAC_REG_SDW(0, 0, 77) +#define TAC_MICBIAS_CFG0 TAC_REG_SDW(0, 0, 79) +#define TAC_MICPREAMP_CFG TAC_REG_SDW(0, 0, 80) +#define TAC_MICBIAS_CFG1 TAC_REG_SDW(0, 0, 81) +#define TAC_CLASSD_CH1_DVOL TAC_REG_SDW(0, 0, 82) +#define TAC_CLASSD_CH1_FGAIN TAC_REG_SDW(0, 0, 83) +#define TAC_CLASSD_CH2_DVOL TAC_REG_SDW(0, 0, 85) +#define TAC_CLASSD_CH2_FGAIN TAC_REG_SDW(0, 0, 86) +#define TAC_GCHP_CH1_DVOL TAC_REG_SDW(0, 0, 88) +#define TAC_GCHP_CH1_FGAIN TAC_REG_SDW(0, 0, 89) +#define TAC_GCHP_CH2_DVOL TAC_REG_SDW(0, 0, 91) +#define TAC_GCHP_CH2_FGAIN TAC_REG_SDW(0, 0, 92) +#define TAC_AMP_LVL_CFG0 TAC_REG_SDW(0, 0, 94) +#define TAC_AMP_LVL_CFG1 TAC_REG_SDW(0, 0, 95) +#define TAC_AMP_LVL_CFG2 TAC_REG_SDW(0, 0, 96) +#define TAC_AMP_LVL_CFG3 TAC_REG_SDW(0, 0, 97) +#define TAC_EFF_MODE_CFG0 TAC_REG_SDW(0, 0, 98) +#define TAC_EFF_MODE_CFG1 TAC_REG_SDW(0, 0, 99) +#define TAC_CLASSD_CFG0 TAC_REG_SDW(0, 0, 100) +#define TAC_CLASSD_CFG1 TAC_REG_SDW(0, 0, 101) +#define TAC_CLASSD_CFG3 TAC_REG_SDW(0, 0, 102) +#define TAC_CLASSD_CFG4 TAC_REG_SDW(0, 0, 103) +#define TAC_CLASSD_CFG5 TAC_REG_SDW(0, 0, 104) +#define TAC_CLASSD_CFG6 TAC_REG_SDW(0, 0, 105) +#define TAC_CLASSD_CFG8 TAC_REG_SDW(0, 0, 106) +#define TAC_ISNS_CFG TAC_REG_SDW(0, 0, 107) +#define TAC_DSP_CFG0 TAC_REG_SDW(0, 0, 108) +#define TAC_DSP_CFG1 TAC_REG_SDW(0, 0, 109) +#define TAC_DSP_CFG2 TAC_REG_SDW(0, 0, 110) +#define TAC_DSP_CFG3 TAC_REG_SDW(0, 0, 111) +#define TAC_JACK_DET_CFG1 TAC_REG_SDW(0, 0, 112) +#define TAC_JACK_DET_CFG2 TAC_REG_SDW(0, 0, 113) +#define TAC_JACK_DET_CFG3 TAC_REG_SDW(0, 0, 114) +#define TAC_JACK_DET_CFG4 TAC_REG_SDW(0, 0, 115) +#define TAC_JACK_DET_CFG7 TAC_REG_SDW(0, 0, 116) +#define TAC_UJ_IMPEDANCE_L TAC_REG_SDW(0, 0, 117) +#define TAC_UJ_IMPEDANCE_R TAC_REG_SDW(0, 0, 118) +#define UJ_IMPEDANCE_L TAC_REG_SDW(0, 0, 119) +#define UJ_IMPEDANCE_R TAC_REG_SDW(0, 0, 120) +#define TAC_GP_ANA_STS TAC_REG_SDW(0, 0, 123) +#define TAC_DEV_ID TAC_REG_SDW(0, 0, 124) +#define TAC_REV_ID TAC_REG_SDW(0, 0, 125) +#define TAC_I2C_CKSUM TAC_REG_SDW(0, 0, 126) +#define TAC_BOOK TAC_REG_SDW(0, 0, 127) + +#define TAC_INT_CFG TAC_REG_SDW(0, 2, 1) +#define TAC_INT_CFG_CLR_REG BIT(3) + +/* smartamp function */ +#define TAC_FUNCTION_ID_SA 0x1 + +#define TAC_SDCA_ENT_ENT0 0x0 +#define TAC_SDCA_ENT_PPU21 0x1 +#define TAC_SDCA_ENT_FU21 0x2 +#define TAC_SDCA_ENT_FU26 0x3 +#define TAC_SDCA_ENT_XU22 0x4 +#define TAC_SDCA_ENT_CS24 0x5 +#define TAC_SDCA_ENT_CS21 0x6 +#define TAC_SDCA_ENT_CS25 0x7 +#define TAC_SDCA_ENT_CS26 0x8 +#define TAC_SDCA_ENT_CS28 0x9 +#define TAC_SDCA_ENT_PPU26 0xa +#define TAC_SDCA_ENT_FU23 0xb +#define TAC_SDCA_ENT_PDE23 0xc +#define TAC_SDCA_ENT_TG23 0x12 +#define TAC_SDCA_ENT_IT21 0x13 +#define TAC_SDCA_ENT_IT29 0x14 +#define TAC_SDCA_ENT_IT26 0x15 +#define TAC_SDCA_ENT_IT28 0x16 +#define TAC_SDCA_ENT_OT24 0x17 +#define TAC_SDCA_ENT_OT23 0x18 +#define TAC_SDCA_ENT_OT25 0x19 +#define TAC_SDCA_ENT_OT28 0x1a +#define TAC_SDCA_ENT_OT27 0x1c +#define TAC_SDCA_ENT_SPE199 0x21 +#define TAC_SDCA_ENT_OT20 0x24 +#define TAC_SDCA_ENT_FU27 0x26 +#define TAC_SDCA_ENT_FU20 0x27 +#define TAC_SDCA_ENT_PDE24 0x2e +#define TAC_SDCA_ENT_PDE27 0x2f +#define TAC_SDCA_ENT_PDE28 0x30 +#define TAC_SDCA_ENT_PDE20 0x31 +#define TAC_SDCA_ENT_SAPU29 0x35 + +/* Control selector definitions */ +#define TAC_SDCA_MASTER_GAIN 0x0B +#define TAC_SDCA_MASTER_MUTE 0x01 +#define TAC_SDCA_CHANNEL_MUTE 0x01 +#define TAC_SDCA_CHANNEL_GAIN 0x02 +#define TAC_SDCA_POSTURENUMBER 0x10 +#define TAC_SDCA_REQUESTED_PS 0x01 +#define TAC_SDCA_ACTUAL_PS 0x10 +#define TAC_SDCA_CHANNEL_VOLUME 0x02 + +/* 2. smart mic function */ +#define TAC_FUNCTION_ID_SM 0x2 + +#define TAC_SDCA_ENT_IT11 0x1 +#define TAC_SDCA_ENT_OT113 0x2 +#define TAC_SDCA_ENT_CS11 0x3 +#define TAC_SDCA_ENT_CS18 0x4 +#define TAC_SDCA_ENT_FU113 0x5 +#define TAC_SDCA_ENT_FU13 0x6 +#define TAC_SDCA_ENT_FU11 0x8 +#define TAC_SDCA_ENT_XU12 0xa +#define TAC_SDCA_ENT_CS113 0xc +#define TAC_SDCA_ENT_CX11 0xf +#define TAC_SDCA_ENT_PDE11 0x12 +#define TAC_SDCA_ENT_PPU11 0x9 + +/* controls */ +#define TAC_SDCA_CTL_USAGE 0x04 +#define TAC_SDCA_CTL_IT_CLUSTER 0x10 +#define TAC_SDCA_CTL_OT_DP_SEL 0x11 +#define TAC_SDCA_CTL_XU_BYPASS 0x01 +/* cx */ +#define TAC_SDCA_CTL_CX_CLK_SEL 0x01 +/* cs */ +#define TAC_SDCA_CTL_CS_CLKVLD 0x02 +#define TAC_SDCA_CTL_CS_SAMP_RATE_IDX 0x10 +/* cs113 end */ +/* ppu */ +#define TAC_SDCA_CTL_PPU_POSTURE_NUM 0x10 + +/* 3. UAJ function */ +#define TAC_FUNCTION_ID_UAJ 0x3 +#define TAC_SDCA_ENT_PDE47 0x35 +#define TAC_SDCA_ENT_PDE34 0x32 +#define TAC_SDCA_ENT_FU41 0x26 /* user */ +#define TAC_SDCA_ENT_IT41 0x07 +#define TAC_SDCA_ENT_XU42 0x2C +#define TAC_SDCA_ENT_CS41 0x30 +#define TAC_SDCA_ENT_OT45 0x0E +#define TAC_SDCA_ENT_IT33 0x03 +#define TAC_SDCA_ENT_OT36 0x0A +#define TAC_SDCA_ENT_FU36 0x28 +#define TAC_SDCA_ENT_CS36 0x2E +#define TAC_SDCA_ENT_GE35 0x3B /* 59 */ + +#define TAC_SDCA_CTL_SEL_MODE 0x1 +#define TAC_SDCA_CTL_DET_MODE 0x2 + +/* 4. HID function */ +#define TAC_FUNCTION_ID_HID 0x4 +#define TAC_SDCA_ENT_HID1 0x1 +/* HID Control Selectors */ +#define TAC_SDCA_CTL_HIDTX_CURRENT_OWNER 0x10 +#define TAC_SDCA_CTL_HIDTX_MESSAGE_OFFSET 0x12 +#define TAC_SDCA_CTL_HIDTX_MESSAGE_LENGTH 0x13 +#define TAC_SDCA_CTL_DETECTED_MODE 0x10 +#define TAC_SDCA_CTL_SELECTED_MODE 0x11 + +#define TAC_BUF_ADDR_HID1 0x44007F80 + +/* DAI interfaces */ +#define TAC5XX2_SPK 0 +#define TAC5XX2_DMIC 2 +#define TAC5XX2_UAJ 3 + +/* Port numbers for DAIs */ +#define TAC_SDW_PORT_NUM_SPK_PLAYBACK 1 +#define TAC_SDW_PORT_NUM_SPK_CAPTURE 2 +#define TAC_SDW_PORT_NUM_DMIC 3 +#define TAC_SDW_PORT_NUM_UAJ_PLAYBACK 4 +#define TAC_SDW_PORT_NUM_UAJ_CAPTURE 7 +#define TAC_SDW_PORT_NUM_IV_SENSE 8 + +#endif --=20 2.34.1 From nobody Tue Jun 16 17:01:46 2026 Received: from MW6PR02CU001.outbound.protection.outlook.com (mail-westus2azon11012044.outbound.protection.outlook.com [52.101.48.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 50437428851; Thu, 30 Apr 2026 14:46:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=52.101.48.44 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777560409; cv=fail; b=DSU89Xo0FwArRuB2jn8isH3S+pUC8s3v4+Xp3wAgh83WRHOKUilWUzWguO4/1VrC/TYFHLp1kPyAhVxsmJmCFPpWQbt9YYQPPYSbIUaogzxBffhTu+oVbgJgc5NsTlt5UgDEpSSbgIshB0ZuNlE1Tq6zRAV1PHdKBBSffeAhuCA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777560409; c=relaxed/simple; bh=vx482gUlFMgc5rAVMRwKvUAM5W3QhxZRsp1PF9XfQgI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=I6qriwF213DReknftxa5noKPcs/K/zekcf3eyWLNRJXYOEoepoWWlLTeCws9GCCHu6ks1HTcchmq1xWG90XaskysrIQ/0e/F/BLqd6tqKw+ROqh2G0CKtZ72/us563SIY4ETcNdFYR5rauSItGEOxLoU4Siy796NgiL7zjPE+mg= 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=MUON9Skv; arc=fail smtp.client-ip=52.101.48.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="MUON9Skv" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=E4+U3bw/G8Rq2+GXHaL2h8UemDnQRMN6g2wvpu55BwxJ2wOsKP5tMSMsNYud29u2AVNnM5PYnw8JFbtNs0HK/trIaK+3xX5KkWTQ2kj3XhH1L646dhGC7oN0Mr50wKg1nIvVVAk282do/ai+fxtvECp4jbJAPciHbXNBHmIqMKpaqtGZhatTr0F8yR8z/5OKjVGVwZecCn8OedS8KAkaXG0og3X8/X+htOG0cGxHM5dH1pf65fNcdX2b0YlkuGD9LTwBPoTJRHdepaorXvKcn55BB9WmEtLJ+HXZLJmobQyjAm/ZWbBaKFmjmCs+SfuE53+Zzfcl1dgOgn1nN7DCRA== 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=E/J2PjjRE8mc8m1kqlZ4pOXYTeuJiscuvOllQ52AXMA=; b=TLs9z5boeO59G74KAmxinuT50jZwUJFj+K/7uuv5A/4sX4jUM7iN1XwqPFZFEklPRA7WcEyoJ66DVjXNHJlC4EU3XtlLjVnYdS2zeXkbtJWb6BK36mzsVz1/LZxPIGAKY6txHETCDTB0/2t65IZl+xh2hr7b5h5gS65PU72usJxTVCzo0MNVKbNjB67CQSNKYLz43oZybQswYQfDiqrPUup0EdK4VyuKqSao9HxsPfVhWlVbJytTlW41pAUzheojDdOetx9L6cG3kGIjgpVETY3U+3NY3lT//nTw7ATZMwW0lkg6fQ5P0JkX7bZMsMbxUpUQDNt55ojAF261FFzFTQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.21.194) smtp.rcpttodomain=linux.dev 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=E/J2PjjRE8mc8m1kqlZ4pOXYTeuJiscuvOllQ52AXMA=; b=MUON9Skvq5rGwCyOUk+z0GyAoBH70So76zm3Tl9na0jT2DfXA5ommf1ixfQti8b/OCRZ80lAmY6T+Kb7SETZB1uXg9ggTUAvbjXmAaZIMIY6TLb3wM3VOCoLQunwTImc2Xoa+irJXZQyJjwmEWLLKRd+/bk50Q56A7RpUSgGOXc= Received: from BN9PR03CA0287.namprd03.prod.outlook.com (2603:10b6:408:f5::22) by LV0PR10MB997686.namprd10.prod.outlook.com (2603:10b6:408:340::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9870.18; Thu, 30 Apr 2026 14:46:44 +0000 Received: from MN1PEPF0000F0E0.namprd04.prod.outlook.com (2603:10b6:408:f5:cafe::e5) by BN9PR03CA0287.outlook.office365.com (2603:10b6:408:f5::22) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9870.22 via Frontend Transport; Thu, 30 Apr 2026 14:46:44 +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 MN1PEPF0000F0E0.mail.protection.outlook.com (10.167.242.38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.18 via Frontend Transport; Thu, 30 Apr 2026 14:46:42 +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; Thu, 30 Apr 2026 09:46:33 -0500 Received: from DFLE207.ent.ti.com (10.64.6.65) 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; Thu, 30 Apr 2026 09:46:33 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) by DFLE207.ent.ti.com (10.64.6.65) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20 via Frontend Transport; Thu, 30 Apr 2026 09:46:33 -0500 Received: from LTPW0EX92E.dhcp.ti.com (ltpw0ex92e.dhcp.ti.com [10.82.30.14]) by lelvem-mr06.itg.ti.com (8.18.1/8.18.1) with ESMTP id 63UEk6Mk1332278; Thu, 30 Apr 2026 09:46:27 -0500 From: Niranjan H Y To: CC: , , , , , , , , , , , , , , , , Niranjan H Y Subject: [PATCH v14 3/4] ASoC: sdw_utils: TI amp utility for tac5xx2 family Date: Thu, 30 Apr 2026 20:15:53 +0530 Message-ID: <20260430144554.1335-4-niranjan.hy@ti.com> X-Mailer: git-send-email 2.33.0.windows.2 In-Reply-To: <20260430144554.1335-1-niranjan.hy@ti.com> References: <20260430144554.1335-1-niranjan.hy@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: MN1PEPF0000F0E0:EE_|LV0PR10MB997686:EE_ X-MS-Office365-Filtering-Correlation-Id: 3905ec2f-996d-4910-4c27-08dea6c74b8a X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|1800799024|376014|82310400026|36860700016|22082099003|18002099003|56012099003; X-Microsoft-Antispam-Message-Info: ELy347+aRmi2hG3kAfA037A1f9GyCEuQ0DfXNmCRCKC7aqBGvQKqaKYrXNeifk+aEPx0NVeii+z2tI3uHa2HE7p/qAfVlnlOrIA5aAdgDAnMYNKMJuMHZyzr63BT0HO4FUVV+NrRdc8uSLNZhP1eR/wA9Huh/UxwHXglkm0At0ofDz2ns44d90cfQ5y6WTwe+DqOHFf62uQ/X/uqAeDlosWWC9Z8VBJ13yTrD323j5WLXBGYcIc8Fr395Zq+ZsCbzbwhLOVlymLMIvv38P6zIx8u4zAqdlxaEl3nv9o0Rm+619XnUN9OBcyuZYLVJMuiIQsAY4mY2ZszoqUz1IbBUse7287qjWaXX3w6UkELLqLw6CnpXi7Vsq4SWmROYOrVd/bNMgyk/FlybT3tyX2JSDOE8edHtBID5l0+9MmwEIQk9mX574+Ojy+8GtEg8MDYCsgPN8EpOMOyN14FND6KK1B+GJPcCd25sdY3apOTStac0c2StiZxMPQHv59flSMDrhvnbyCHqqON2XyllqdX4FBqsoA5veCbkMSw2Qp2XB1w72A7bCbwdg+NUxCnPut9h2JpJFc6PkjTSQVBgL1pZrt5OFuGCzA55SJ5DsBmNQBMdLItncXTZ37X4zcSj/x2Oah9PoW5TYe1WVu50yi/yvyOdKX2JQPlWdLkJdqSQmKrxLhgAS238g5a5g3jGyttPCvlsmWK5s68DRT4WFQ3yttokYi7cZHuRRNtpPUKMbfcXyR+GY8WOOs8h5YCQDZxgaLo7G9Qop5Pl7qqGttDVg== 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)(7416014)(1800799024)(376014)(82310400026)(36860700016)(22082099003)(18002099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: wCr3o3RPoe9MAe0xr36AxA5u0vwRCQYD92dtC2pdzrndJZMsgMLkI925aupD7WER55wyCfisL2nxTlDnw/gNoZRoEC/V8wEVDxLjrSoag1I3uPWXxbAGux+0iv0+2deJJ9jpc8dW+y9mcg9BhjUwZ3PRNKTncY942zyhJc3b1w6RfJVSdGsa0BdJD7VleplI3EHQA0fkL283bf8/dFwRCm/KGm4zI4Q38gqqwlMgUbwTlgfZJi0L18RaXj8v+bZCNMv/Nz4EckY9v+IC18z3NdtmvZj/OEGaUK+amBIqa3JOAOMlo3mNxTCgIjMLebZRLK4JUl3pxqJBs+ye+HvdOO41B+eOZQQhCQZsjREvaSavDvhn10W3etDSp7aA2lhTLeVqwoMgsNYWigR6nWEBgTc+swC4cRNy7AaahC7TdPBo0DGzKzJ7h91L9Rk5SVBu X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Apr 2026 14:46:42.8094 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 3905ec2f-996d-4910-4c27-08dea6c74b8a 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: MN1PEPF0000F0E0.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: LV0PR10MB997686 Content-Type: text/plain; charset="utf-8" Add TI amp utility for supporting the tac5xx2 family of devices to support tac5572, tac5672, tac5682 and tas2883 Signed-off-by: Niranjan H Y Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart --- v14: - Resending complete series (v13 1/4 was accidentally sent alone) - no change v13: - no change v12: - no change --- include/sound/soc_sdw_utils.h | 4 + sound/soc/sdw_utils/soc_sdw_ti_amp.c | 144 ++++++++++++++++++++++++- sound/soc/sdw_utils/soc_sdw_utils.c | 151 +++++++++++++++++++++++++++ 3 files changed, 298 insertions(+), 1 deletion(-) diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index 489083183..d713ab2f6 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -272,7 +272,11 @@ int asoc_sdw_ti_amp_init(struct snd_soc_card *card, struct asoc_sdw_codec_info *info, bool playback); int asoc_sdw_ti_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_s= oc_dai *dai); +int asoc_sdw_ti_tac5xx2_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai); int asoc_sdw_ti_amp_initial_settings(struct snd_soc_card *card, const char *name_prefix); +int asoc_sdw_ti_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_= soc_dai *dai); +int asoc_sdw_ti_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct= snd_soc_dai *dai); =20 #endif diff --git a/sound/soc/sdw_utils/soc_sdw_ti_amp.c b/sound/soc/sdw_utils/soc= _sdw_ti_amp.c index 488ef2ef4..514340a3e 100644 --- a/sound/soc/sdw_utils/soc_sdw_ti_amp.c +++ b/sound/soc/sdw_utils/soc_sdw_ti_amp.c @@ -7,12 +7,15 @@ =20 #include #include -#include +#include +#include #include #include +#include #include =20 #define TIAMP_SPK_VOLUME_0DB 200 +#define TAC5XX2_WIDGET_NAME_MAX 32 =20 int asoc_sdw_ti_amp_initial_settings(struct snd_soc_card *card, const char *name_prefix) @@ -95,3 +98,142 @@ int asoc_sdw_ti_amp_init(struct snd_soc_card *card, return 0; } EXPORT_SYMBOL_NS(asoc_sdw_ti_amp_init, "SND_SOC_SDW_UTILS"); + +static int asoc_sdw_ti_add_tac5xx2_routes(struct snd_soc_dapm_context *dap= m, + const char *name_prefix) +{ + struct snd_soc_dapm_route routes[2]; + char left_widget[TAC5XX2_WIDGET_NAME_MAX]; + char right_widget[TAC5XX2_WIDGET_NAME_MAX]; + int ret; + + if (strlen(name_prefix) > (TAC5XX2_WIDGET_NAME_MAX - 7)) + return -ENAMETOOLONG; + + ret =3D scnprintf(left_widget, sizeof(left_widget), "%s SPK_L", name_pref= ix); + if (ret <=3D 0) + return -EINVAL; + + ret =3D scnprintf(right_widget, sizeof(right_widget), "%s SPK_R", name_pr= efix); + if (ret <=3D 0) + return -EINVAL; + + routes[0] =3D (struct snd_soc_dapm_route){"Left Spk", NULL, left_widget}; + routes[1] =3D (struct snd_soc_dapm_route){"Right Spk", NULL, right_widget= }; + + return snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes)); +} + +int asoc_sdw_ti_tac5xx2_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, + struct snd_soc_dai *dai) +{ + struct snd_soc_card *card =3D rtd->card; + struct snd_soc_dapm_context *dapm =3D snd_soc_card_to_dapm(card); + int ret, i; + struct snd_soc_dai *codec_dai; + const char *prefix; + + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (!strstr(codec_dai->name, "tac5") && + !strstr(codec_dai->name, "tas2883")) + continue; + + prefix =3D codec_dai->component->name_prefix; + if (!prefix) { + dev_warn(card->dev, + "No name prefix found for codec DAI: %s\n", + codec_dai->name); + continue; + } + ret =3D asoc_sdw_ti_add_tac5xx2_routes(dapm, prefix); + if (ret) { + dev_err(card->dev, "Failed to add routes for %s: %d\n", + prefix, ret); + return ret; + } + } + + dev_dbg(card->dev, "Added TAC5XX2 speaker routes\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(asoc_sdw_ti_tac5xx2_spk_rtd_init); + +int asoc_sdw_ti_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_= soc_dai *dai) +{ + struct snd_soc_card *card =3D rtd->card; + struct snd_soc_component *component; + char *mic_name; + + component =3D dai->component; + mic_name =3D devm_kasprintf(card->dev, GFP_KERNEL, "%s", component->name_= prefix); + if (!mic_name) + return -ENOMEM; + + card->components =3D devm_kasprintf(card->dev, GFP_KERNEL, + "%s mic:%s", card->components, + mic_name); + if (!card->components) + return -ENOMEM; + + dev_dbg(card->dev, "card->components: %s\n", card->components); + + return 0; +} +EXPORT_SYMBOL_NS(asoc_sdw_ti_dmic_rtd_init, "SND_SOC_SDW_UTILS"); + +static struct snd_soc_jack_pin ti_sdca_jack_pins[] =3D { + { + .pin =3D "Headphone", + .mask =3D SND_JACK_HEADPHONE, + }, + { + .pin =3D "Headset Mic", + .mask =3D SND_JACK_MICROPHONE, + }, +}; + +int asoc_sdw_ti_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct= snd_soc_dai *dai) +{ + struct snd_soc_card *card =3D rtd->card; + struct asoc_sdw_mc_private *ctx =3D snd_soc_card_get_drvdata(card); + struct snd_soc_component *component; + struct snd_soc_jack *jack; + int ret; + + component =3D dai->component; + + card->components =3D devm_kasprintf(card->dev, GFP_KERNEL, + "%s hs:%s", card->components, + component->name_prefix); + if (!card->components) + return -ENOMEM; + + ret =3D snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3 | SND_JACK_BTN_4, + &ctx->sdw_headset, + ti_sdca_jack_pins, + ARRAY_SIZE(ti_sdca_jack_pins)); + if (ret) { + dev_err(rtd->card->dev, "Jack create failed%d\n", ret); + return ret; + } + + jack =3D &ctx->sdw_headset; + + snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); + snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); + snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); + snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); + snd_jack_set_key(jack->jack, SND_JACK_BTN_4, KEY_NEXTSONG); + + ret =3D snd_soc_component_set_jack(component, jack, NULL); + if (ret) + dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", + ret); + + return ret; +} +EXPORT_SYMBOL_NS(asoc_sdw_ti_sdca_jack_rtd_init, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_= sdw_utils.c index 1637cc3f3..d74624efc 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -72,6 +72,157 @@ static const struct snd_kcontrol_new rt700_controls[] = =3D { }; =20 struct asoc_sdw_codec_info codec_info_list[] =3D { + { + .vendor_id =3D 0x0102, + .part_id =3D 0x5572, + .name_prefix =3D "tac5572", + .dais =3D { + { + /* speaker */ + .direction =3D {true, false}, + .dai_name =3D "tac5xx2-aif1", + .dai_type =3D SOC_SDW_DAI_TYPE_AMP, + .dailink =3D {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init =3D asoc_sdw_ti_amp_init, + .rtd_init =3D asoc_sdw_ti_tac5xx2_spk_rtd_init, + .controls =3D lr_spk_controls, + .num_controls =3D ARRAY_SIZE(lr_spk_controls), + .widgets =3D lr_spk_widgets, + .num_widgets =3D ARRAY_SIZE(lr_spk_widgets), + }, + { + /* mic */ + .direction =3D {false, true}, + .dai_name =3D "tac5xx2-aif2", + .dai_type =3D SOC_SDW_DAI_TYPE_MIC, + .dailink =3D {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init =3D asoc_sdw_ti_dmic_rtd_init, + }, + { + /* UAJ */ + .direction =3D {true, true}, + .dai_name =3D "tac5xx2-aif3", + .dai_type =3D SOC_SDW_DAI_TYPE_JACK, + .dailink =3D {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .controls =3D generic_jack_controls, + .num_controls =3D ARRAY_SIZE(generic_jack_controls), + .widgets =3D generic_jack_widgets, + .num_widgets =3D ARRAY_SIZE(generic_jack_widgets), + .rtd_init =3D asoc_sdw_ti_sdca_jack_rtd_init, + }, + }, + .dai_num =3D 3, + }, + { + .vendor_id =3D 0x0102, + .part_id =3D 0x5672, + .name_prefix =3D "tac5672", + .dais =3D { + { + /* speaker with IV sense feedback */ + .direction =3D {true, true}, + .dai_name =3D "tac5xx2-aif1", + .dai_type =3D SOC_SDW_DAI_TYPE_AMP, + .dailink =3D {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init =3D asoc_sdw_ti_amp_init, + .rtd_init =3D asoc_sdw_ti_tac5xx2_spk_rtd_init, + .controls =3D lr_spk_controls, + .num_controls =3D ARRAY_SIZE(lr_spk_controls), + .widgets =3D lr_spk_widgets, + .num_widgets =3D ARRAY_SIZE(lr_spk_widgets), + }, + { + /* mic */ + .direction =3D {false, true}, + .dai_name =3D "tac5xx2-aif2", + .dai_type =3D SOC_SDW_DAI_TYPE_MIC, + .dailink =3D {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init =3D asoc_sdw_ti_dmic_rtd_init, + }, + { + /* UAJ */ + .direction =3D {true, true}, + .dai_name =3D "tac5xx2-aif3", + .dai_type =3D SOC_SDW_DAI_TYPE_JACK, + .dailink =3D {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .controls =3D generic_jack_controls, + .num_controls =3D ARRAY_SIZE(generic_jack_controls), + .widgets =3D generic_jack_widgets, + .num_widgets =3D ARRAY_SIZE(generic_jack_widgets), + .rtd_init =3D asoc_sdw_ti_sdca_jack_rtd_init, + }, + }, + .dai_num =3D 3, + }, + { + .vendor_id =3D 0x0102, + .part_id =3D 0x5682, + .name_prefix =3D "tac5682", + .dais =3D { + { + /* speaker with echo reference feedback */ + .direction =3D {true, true}, + .dai_name =3D "tac5xx2-aif1", + .dai_type =3D SOC_SDW_DAI_TYPE_AMP, + .dailink =3D {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .init =3D asoc_sdw_ti_amp_init, + .rtd_init =3D asoc_sdw_ti_tac5xx2_spk_rtd_init, + .controls =3D lr_spk_controls, + .num_controls =3D ARRAY_SIZE(lr_spk_controls), + .widgets =3D lr_spk_widgets, + .num_widgets =3D ARRAY_SIZE(lr_spk_widgets), + }, + { + /* mic */ + .direction =3D {false, true}, + .dai_name =3D "tac5xx2-aif2", + .dai_type =3D SOC_SDW_DAI_TYPE_MIC, + .dailink =3D {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init =3D asoc_sdw_ti_dmic_rtd_init, + }, + { + /* UAJ */ + .direction =3D {true, true}, + .dai_name =3D "tac5xx2-aif3", + .dai_type =3D SOC_SDW_DAI_TYPE_JACK, + .dailink =3D {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, + .controls =3D generic_jack_controls, + .num_controls =3D ARRAY_SIZE(generic_jack_controls), + .widgets =3D generic_jack_widgets, + .num_widgets =3D ARRAY_SIZE(generic_jack_widgets), + .rtd_init =3D asoc_sdw_ti_sdca_jack_rtd_init, + }, + }, + .dai_num =3D 3, + }, + { + .vendor_id =3D 0x0102, + .part_id =3D 0x2883, + .name_prefix =3D "tas2883", + .dais =3D { + { + .direction =3D {true, false}, + .dai_name =3D "tac5xx2-aif1", + .dai_type =3D SOC_SDW_DAI_TYPE_AMP, + .dailink =3D {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + .init =3D asoc_sdw_ti_amp_init, + .rtd_init =3D asoc_sdw_ti_tac5xx2_spk_rtd_init, + .controls =3D lr_spk_controls, + .num_controls =3D ARRAY_SIZE(lr_spk_controls), + .widgets =3D lr_spk_widgets, + .num_widgets =3D ARRAY_SIZE(lr_spk_widgets), + }, + { + /* mic */ + .direction =3D {false, true}, + .dai_name =3D "tac5xx2-aif2", + .dai_type =3D SOC_SDW_DAI_TYPE_MIC, + .dailink =3D {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + .rtd_init =3D asoc_sdw_ti_dmic_rtd_init, + }, + }, + .dai_num =3D 2, + }, { .vendor_id =3D 0x0102, .part_id =3D 0x0000, /* TAS2783A */ --=20 2.34.1 From nobody Tue Jun 16 17:01: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 C8F5842B743; Thu, 30 Apr 2026 14:46:51 +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=1777560414; cv=fail; b=YGdOaKlLmA8414H80Vb8hLlHBHl568D9WwioszkgDIeoFif3HbabaSxQKr3yKZWek3sWl2FVN0c38JRyzhs4WyBeOgWhn+rDXj1YJF+4knQgaArf0ODPSsRNCW7HyHawH/WIuVfdUiyLx8qkfQEFmB9XO/d/LWUQQhFOJ4HgRl4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777560414; c=relaxed/simple; bh=/v69QSVjnqtgQKgUvHzvHbHXvpYLopRR/uq+ohnsrBo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=d99zZsZlR6MPEaTxXZx+QkHNlyHvg6rYQzW4VaFoyV46KUDpQcrUT2t+J50uMsj8Ar7/4eiQ9F6w1dKkzos77fkVD4435xYLu23ohWtXuYKed1ElSUWDX0bavIqlX/cozdnRlkQcoKbrlGL+QdsT8+3wMgKOU1vs8cJUUsBDpYY= 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=UaWdDs6i; 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="UaWdDs6i" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=q6GJQF2LHZhufWO92ktO6UvxY0K+/mQODsNTzOsE51kmaga+fTb/xRz336e5LZdcvgd0H0sY6AgAXbdJqimAP2xzrLu6GQ8YSN7olfh2/PL0qDExXb1xeSrJGfNrrezXUcPtqjGf3gRxsYuP6viZgIeieOpMgCLMgUwe1ZcXOs1BBOEa6W8eKsD0JnoapJmzYFoI0UHtATODNWViB8QDktDm2iRv4hO03PMBXVt2eosZ+jCJQdHT1h0mpNq2k5SqlIrTIB6KIR+ZZf3Xx60am+VVwl9PDH1yQvukChy0O56IADD7GZ/XLCmwwjTjyF0ulBQfhuSieugOfvnfoik5oA== 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=+rSrjWIxzX7WPqXxjrP7r4J7S4iv0+pDMpctC1GSN9I=; b=iNFxpNJtsteX2E1VYoVw/iohqcwxvpfqJ31McIb5SmUCrpIwpUUkCdkPY9btZ26pcTz5Hyc0/+BG4cizJWlbBbwoMKyRAQtwWofv/7HraNKkaoNNz0Yxd4Dzmn9tTwpXUTheW0zj0byzTIALbX4qSnIFOiG9UicedFtw0bC3zN2TCd3rp3SSouVuEXhN2TNwVrXf2109urOonJKcOl21sQugQ+KczlYF//MLC94TKeoN/OGPv1iUlrXatqkYNIOaIXqc/F/mdmnvAncLVkh7PGzvI/qvXYm7Gk9DpOp59IMCpKJTgWpVq6RHHrWwF0xJyx1cH2AXYSXrGzpqndo11Q== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 198.47.21.194) smtp.rcpttodomain=linux.dev 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=+rSrjWIxzX7WPqXxjrP7r4J7S4iv0+pDMpctC1GSN9I=; b=UaWdDs6irORmQ+Doj5N2W3Svwd1GHG5MDUVwSKlF8RKKf/WRaGr3gFwo3HDDp3mMBFeU0Lrb7FngtBKn0cZCqcwno3qhekuoThvOz3XWgRiwF06BeR2oW3X5E5pPmWzyOuQjlCIk8hp9ouoaFsVRhdHm3wRksruuIAg+u7Y6RIg= Received: from BN9PR03CA0277.namprd03.prod.outlook.com (2603:10b6:408:f5::12) by BN0PR10MB4904.namprd10.prod.outlook.com (2603:10b6:408:125::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9870.20; Thu, 30 Apr 2026 14:46:47 +0000 Received: from MN1PEPF0000F0E0.namprd04.prod.outlook.com (2603:10b6:408:f5:cafe::6c) by BN9PR03CA0277.outlook.office365.com (2603:10b6:408:f5::12) with Microsoft SMTP Server (version=TLS1_3, cipher=TLS_AES_256_GCM_SHA384) id 15.20.9846.30 via Frontend Transport; Thu, 30 Apr 2026 14:46:47 +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 MN1PEPF0000F0E0.mail.protection.outlook.com (10.167.242.38) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9846.18 via Frontend Transport; Thu, 30 Apr 2026 14:46:45 +0000 Received: from DFLE214.ent.ti.com (10.64.6.72) 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; Thu, 30 Apr 2026 09:46:40 -0500 Received: from DFLE202.ent.ti.com (10.64.6.60) by DFLE214.ent.ti.com (10.64.6.72) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.2562.20; Thu, 30 Apr 2026 09:46:39 -0500 Received: from lelvem-mr06.itg.ti.com (10.180.75.8) 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; Thu, 30 Apr 2026 09:46:39 -0500 Received: from LTPW0EX92E.dhcp.ti.com (ltpw0ex92e.dhcp.ti.com [10.82.30.14]) by lelvem-mr06.itg.ti.com (8.18.1/8.18.1) with ESMTP id 63UEk6Ml1332278; Thu, 30 Apr 2026 09:46:34 -0500 From: Niranjan H Y To: CC: , , , , , , , , , , , , , , , , Niranjan H Y Subject: [PATCH v14 4/4] ASoC: tac5xx2-sdw: ACPI match for intel mtl platform Date: Thu, 30 Apr 2026 20:15:54 +0530 Message-ID: <20260430144554.1335-5-niranjan.hy@ti.com> X-Mailer: git-send-email 2.33.0.windows.2 In-Reply-To: <20260430144554.1335-1-niranjan.hy@ti.com> References: <20260430144554.1335-1-niranjan.hy@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: MN1PEPF0000F0E0:EE_|BN0PR10MB4904:EE_ X-MS-Office365-Filtering-Correlation-Id: 375fc814-b781-467f-3531-08dea6c74d44 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|376014|36860700016|82310400026|1800799024|18002099003|22082099003|56012099003; X-Microsoft-Antispam-Message-Info: WSHsBLF2VFFFUVX5m6pmiyb48VMlhARFKzez1J2GdKP4BUZ5jUz+WbdNm5WaasK+K3KS3XG5q/HCsrhdd3cQrNeyafBn8EVfZTQDbd8LO6DDiM3m0BhEohzRe1sSM/ieJm3+U5juGwY7T7KZMhm6fFzW9dHc46R71hfW21zxIrBrW8g15r+1CifBVYkFrpoI/kzCZRQaOIM+EZX6kweAKyt+9WQ923Wanb6VwiRtSbjPzqyHlWpFv5l5aBXLa9Lzlxc1LCbs3r9HzsdbFNsUd+YFGcqyAF+3TaLJHW21v6pb2RHjOd/hEboU0/JVjqTPMFAttaqBHYYXqgs6vuck4FHSs47M6VAxHEvxC+X/g55AGYApKoYTCBmt51S0E44QAWxCPTVI4A5B5szrMWZSllV3Epy8Sj0FDGyiyyC4DJoOlpDr7Y58eyP7aiCHK0WoOQO0F3O3MK6z4MaXYCbOWoIfqj6Wztmc5RGWIMQn7HqRphuhBcXTmrNiV3ldiXnHZEudU3YM1/zG3nUS0llZ3cSbBBy18xJ1IuO5MduklFID5mWyMHdTLIAPnJ7rDld+34L2Gc5hI5HTwZanYjq5Vz86tEt5OKAvGc/6LkiU2LoZlvnz2Ugq8MAroCZvDImtUUqR1zES7I5qcyqe12a2WVHakQ4FDXlgxppuJT2RDOZnt8LTP3naiyPMs9U4hAyuXLZlRrdGOwaZf1mXOv21UnoElNmtc0EcGUHFzPioBpQhujn1vdq930snCsWa6JJK3t30ldowIp225WnZmsezQA== 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)(7416014)(376014)(36860700016)(82310400026)(1800799024)(18002099003)(22082099003)(56012099003);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: MC5LVlk4q9fpSkPohq9j4oG9U/dFayP0m/5XCg2zMpAM7VXKuF1ltQPdyz9XPIMBe43DN1hhbEItruRZPjKeNOpNKLCaum2Y6JDn6prUjO1QGx3SRYPQNPLQfLhGAnpVNOG8fX2jl1sqYnylslWzP/RUWX3JcImQocwYJBHJ1+lzS+yLIiICHESYBQVUt9wWs5x+8/YI9AyCyk9RRlxcw+jKfG3OsdKDcijoSC/tCDdr0ubgs4yA+Bqee8gMNTuX77PWIz4PZxF8g6o8srPwjaHcjqC354KlrT4Um8OMKKU/MQEcamsB8iRlykuF8Jx01k0ufmgy+IEjT0fna69MyNUFeWTjacUR7gNDnFwbZMoL67c4sNssjxv1Y6iiIlKhjUEcuteTD5ZdSZ1AWqqhXE9H1jR5tWTxuYGn4hZQiOouWRVFlH66XTJOszZYRUnk X-OriginatorOrg: ti.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Apr 2026 14:46:45.7048 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 375fc814-b781-467f-3531-08dea6c74d44 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: MN1PEPF0000F0E0.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN0PR10MB4904 Content-Type: text/plain; charset="utf-8" Add acpi match entries to support TI's tac5572, tas2883, tac5672 and tac5682 on link 0 on MTL machine. Signed-off-by: Niranjan H Y Reviewed-by: Bard Liao Reviewed-by: Pierre-Louis Bossart --- 14: - Resending complete series (v13 1/4 was accidentally sent alone) - no change v13: - no change --- .../intel/common/soc-acpi-intel-mtl-match.c | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/= intel/common/soc-acpi-intel-mtl-match.c index 72c35e730..2e4222456 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -122,6 +122,42 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoi= nt =3D { .group_id =3D 1, }; =20 +static const struct snd_soc_acpi_endpoint tac5xx2_endpoints[] =3D { + { /* Playback Endpoint */ + .num =3D 0, + .aggregated =3D 0, + .group_position =3D 0, + .group_id =3D 0, + }, + { /* Mic Capture Endpoint */ + .num =3D 1, + .aggregated =3D 0, + .group_position =3D 0, + .group_id =3D 0, + }, + { /* UAJ-HP with Mic Endpoint */ + .num =3D 2, + .aggregated =3D 0, + .group_position =3D 0, + .group_id =3D 0, + }, +}; + +static const struct snd_soc_acpi_endpoint tas2883_endpoints[] =3D { + { /* Playback Endpoint */ + .num =3D 0, + .aggregated =3D 0, + .group_position =3D 0, + .group_id =3D 0, + }, + { /* Mic Capture Endpoint */ + .num =3D 1, + .aggregated =3D 0, + .group_position =3D 0, + .group_id =3D 0, + }, +}; + static const struct snd_soc_acpi_endpoint rt712_endpoints[] =3D { { .num =3D 0, @@ -1011,6 +1047,33 @@ static const struct snd_soc_acpi_adr_device cs42l42_= 0_adr[] =3D { } }; =20 +static const struct snd_soc_acpi_adr_device tac5572_0_adr[] =3D { + { + .adr =3D 0x0000300102557201ull, + .num_endpoints =3D ARRAY_SIZE(tac5xx2_endpoints), + .endpoints =3D tac5xx2_endpoints, + .name_prefix =3D "tac5572" + } +}; + +static const struct snd_soc_acpi_adr_device tac5672_0_adr[] =3D { + { + .adr =3D 0x0000300102567201ull, + .num_endpoints =3D ARRAY_SIZE(tac5xx2_endpoints), + .endpoints =3D tac5xx2_endpoints, + .name_prefix =3D "tac5672" + } +}; + +static const struct snd_soc_acpi_adr_device tac5682_0_adr[] =3D { + { + .adr =3D 0x0000300102568201ull, + .num_endpoints =3D ARRAY_SIZE(tac5xx2_endpoints), + .endpoints =3D tac5xx2_endpoints, + .name_prefix =3D "tac5682" + } +}; + static const struct snd_soc_acpi_adr_device tas2783_0_adr[] =3D { { .adr =3D 0x00003c0102000001ull, @@ -1035,9 +1098,45 @@ static const struct snd_soc_acpi_adr_device tas2783_= 0_adr[] =3D { .num_endpoints =3D 1, .endpoints =3D &spk_r_endpoint, .name_prefix =3D "tas2783-4" + }, +}; + +static const struct snd_soc_acpi_adr_device tas2883_0_adr[] =3D { + { + .adr =3D 0x0000300102288301ull, + .num_endpoints =3D ARRAY_SIZE(tas2883_endpoints), + .endpoints =3D tas2883_endpoints, + .name_prefix =3D "tas2883" } }; =20 +static const struct snd_soc_acpi_link_adr tac5572_l0[] =3D { + { + .mask =3D BIT(0), + .num_adr =3D ARRAY_SIZE(tac5572_0_adr), + .adr_d =3D tac5572_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr tac5672_l0[] =3D { + { + .mask =3D BIT(0), + .num_adr =3D ARRAY_SIZE(tac5672_0_adr), + .adr_d =3D tac5672_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr tac5682_l0[] =3D { + { + .mask =3D BIT(0), + .num_adr =3D ARRAY_SIZE(tac5682_0_adr), + .adr_d =3D tac5682_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr tas2783_link0[] =3D { { .mask =3D BIT(0), @@ -1047,6 +1146,15 @@ static const struct snd_soc_acpi_link_adr tas2783_li= nk0[] =3D { {} }; =20 +static const struct snd_soc_acpi_link_adr tas2883_l0[] =3D { + { + .mask =3D BIT(0), + .num_adr =3D ARRAY_SIZE(tas2883_0_adr), + .adr_d =3D tas2883_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr cs42l42_link0_max98363_link2[] = =3D { /* Expected order: jack -> amp */ { @@ -1208,12 +1316,36 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw= _machines[] =3D { .drv_name =3D "sof_sdw", .sof_tplg_filename =3D "sof-mtl-rt715-rt711-rt1308-mono.tplg", }, + { + .link_mask =3D BIT(0), + .links =3D tac5572_l0, + .drv_name =3D "sof_sdw", + .sof_tplg_filename =3D "sof-mtl-tac5572.tplg", + }, + { + .link_mask =3D BIT(0), + .links =3D tac5672_l0, + .drv_name =3D "sof_sdw", + .sof_tplg_filename =3D "sof-mtl-tac5672.tplg", + }, + { + .link_mask =3D BIT(0), + .links =3D tac5682_l0, + .drv_name =3D "sof_sdw", + .sof_tplg_filename =3D "sof-mtl-tac5682.tplg", + }, { .link_mask =3D BIT(0), .links =3D tas2783_link0, .drv_name =3D "sof_sdw", .sof_tplg_filename =3D "sof-mtl-tas2783.tplg", }, + { + .link_mask =3D BIT(0), + .links =3D tas2883_l0, + .drv_name =3D "sof_sdw", + .sof_tplg_filename =3D "sof-mtl-tas2883.tplg", + }, { .link_mask =3D GENMASK(3, 0), .links =3D mtl_rt713_l0_rt1316_l12_rt1713_l3, --=20 2.34.1