18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <drm/drm_dp_helper.h>
128c2ecf20Sopenharmony_ci#include <drm/drm_edid.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "dp_catalog.h"
158c2ecf20Sopenharmony_ci#include "dp_audio.h"
168c2ecf20Sopenharmony_ci#include "dp_panel.h"
178c2ecf20Sopenharmony_ci#include "dp_display.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define HEADER_BYTE_2_BIT	 0
208c2ecf20Sopenharmony_ci#define PARITY_BYTE_2_BIT	 8
218c2ecf20Sopenharmony_ci#define HEADER_BYTE_1_BIT	16
228c2ecf20Sopenharmony_ci#define PARITY_BYTE_1_BIT	24
238c2ecf20Sopenharmony_ci#define HEADER_BYTE_3_BIT	16
248c2ecf20Sopenharmony_ci#define PARITY_BYTE_3_BIT	24
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct dp_audio_private {
278c2ecf20Sopenharmony_ci	struct platform_device *audio_pdev;
288c2ecf20Sopenharmony_ci	struct platform_device *pdev;
298c2ecf20Sopenharmony_ci	struct dp_catalog *catalog;
308c2ecf20Sopenharmony_ci	struct dp_panel *panel;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	bool engine_on;
338c2ecf20Sopenharmony_ci	u32 channels;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	struct dp_audio dp_audio;
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic u8 dp_audio_get_g0_value(u8 data)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	u8 c[4];
418c2ecf20Sopenharmony_ci	u8 g[4];
428c2ecf20Sopenharmony_ci	u8 ret_data = 0;
438c2ecf20Sopenharmony_ci	u8 i;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
468c2ecf20Sopenharmony_ci		c[i] = (data >> i) & 0x01;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	g[0] = c[3];
498c2ecf20Sopenharmony_ci	g[1] = c[0] ^ c[3];
508c2ecf20Sopenharmony_ci	g[2] = c[1];
518c2ecf20Sopenharmony_ci	g[3] = c[2];
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
548c2ecf20Sopenharmony_ci		ret_data = ((g[i] & 0x01) << i) | ret_data;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return ret_data;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic u8 dp_audio_get_g1_value(u8 data)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	u8 c[4];
628c2ecf20Sopenharmony_ci	u8 g[4];
638c2ecf20Sopenharmony_ci	u8 ret_data = 0;
648c2ecf20Sopenharmony_ci	u8 i;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
678c2ecf20Sopenharmony_ci		c[i] = (data >> i) & 0x01;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	g[0] = c[0] ^ c[3];
708c2ecf20Sopenharmony_ci	g[1] = c[0] ^ c[1] ^ c[3];
718c2ecf20Sopenharmony_ci	g[2] = c[1] ^ c[2];
728c2ecf20Sopenharmony_ci	g[3] = c[2] ^ c[3];
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++)
758c2ecf20Sopenharmony_ci		ret_data = ((g[i] & 0x01) << i) | ret_data;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return ret_data;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic u8 dp_audio_calculate_parity(u32 data)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	u8 x0 = 0;
838c2ecf20Sopenharmony_ci	u8 x1 = 0;
848c2ecf20Sopenharmony_ci	u8 ci = 0;
858c2ecf20Sopenharmony_ci	u8 iData = 0;
868c2ecf20Sopenharmony_ci	u8 i = 0;
878c2ecf20Sopenharmony_ci	u8 parity_byte;
888c2ecf20Sopenharmony_ci	u8 num_byte = (data & 0xFF00) > 0 ? 8 : 2;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	for (i = 0; i < num_byte; i++) {
918c2ecf20Sopenharmony_ci		iData = (data >> i*4) & 0xF;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		ci = iData ^ x1;
948c2ecf20Sopenharmony_ci		x1 = x0 ^ dp_audio_get_g1_value(ci);
958c2ecf20Sopenharmony_ci		x0 = dp_audio_get_g0_value(ci);
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	parity_byte = x1 | (x0 << 4);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	return parity_byte;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic u32 dp_audio_get_header(struct dp_catalog *catalog,
1048c2ecf20Sopenharmony_ci		enum dp_catalog_audio_sdp_type sdp,
1058c2ecf20Sopenharmony_ci		enum dp_catalog_audio_header_type header)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	catalog->sdp_type = sdp;
1088c2ecf20Sopenharmony_ci	catalog->sdp_header = header;
1098c2ecf20Sopenharmony_ci	dp_catalog_audio_get_header(catalog);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	return catalog->audio_data;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void dp_audio_set_header(struct dp_catalog *catalog,
1158c2ecf20Sopenharmony_ci		u32 data,
1168c2ecf20Sopenharmony_ci		enum dp_catalog_audio_sdp_type sdp,
1178c2ecf20Sopenharmony_ci		enum dp_catalog_audio_header_type header)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	catalog->sdp_type = sdp;
1208c2ecf20Sopenharmony_ci	catalog->sdp_header = header;
1218c2ecf20Sopenharmony_ci	catalog->audio_data = data;
1228c2ecf20Sopenharmony_ci	dp_catalog_audio_set_header(catalog);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void dp_audio_stream_sdp(struct dp_audio_private *audio)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
1288c2ecf20Sopenharmony_ci	u32 value, new_value;
1298c2ecf20Sopenharmony_ci	u8 parity_byte;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	/* Config header and parity byte 1 */
1328c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
1338c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	new_value = 0x02;
1368c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
1378c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_1_BIT)
1388c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_1_BIT));
1398c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
1408c2ecf20Sopenharmony_ci			value, parity_byte);
1418c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
1428c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	/* Config header and parity byte 2 */
1458c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
1468c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
1478c2ecf20Sopenharmony_ci	new_value = value;
1488c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
1498c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_2_BIT)
1508c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_2_BIT));
1518c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
1528c2ecf20Sopenharmony_ci			value, parity_byte);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
1558c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* Config header and parity byte 3 */
1588c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
1598c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	new_value = audio->channels - 1;
1628c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
1638c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_3_BIT)
1648c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_3_BIT));
1658c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
1668c2ecf20Sopenharmony_ci		value, parity_byte);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
1698c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic void dp_audio_timestamp_sdp(struct dp_audio_private *audio)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
1758c2ecf20Sopenharmony_ci	u32 value, new_value;
1768c2ecf20Sopenharmony_ci	u8 parity_byte;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	/* Config header and parity byte 1 */
1798c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
1808c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	new_value = 0x1;
1838c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
1848c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_1_BIT)
1858c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_1_BIT));
1868c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
1878c2ecf20Sopenharmony_ci		value, parity_byte);
1888c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
1898c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	/* Config header and parity byte 2 */
1928c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
1938c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	new_value = 0x17;
1968c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
1978c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_2_BIT)
1988c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_2_BIT));
1998c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
2008c2ecf20Sopenharmony_ci			value, parity_byte);
2018c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
2028c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* Config header and parity byte 3 */
2058c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
2068c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	new_value = (0x0 | (0x11 << 2));
2098c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
2108c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_3_BIT)
2118c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_3_BIT));
2128c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
2138c2ecf20Sopenharmony_ci			value, parity_byte);
2148c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
2158c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic void dp_audio_infoframe_sdp(struct dp_audio_private *audio)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
2218c2ecf20Sopenharmony_ci	u32 value, new_value;
2228c2ecf20Sopenharmony_ci	u8 parity_byte;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* Config header and parity byte 1 */
2258c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
2268c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	new_value = 0x84;
2298c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
2308c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_1_BIT)
2318c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_1_BIT));
2328c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
2338c2ecf20Sopenharmony_ci			value, parity_byte);
2348c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
2358c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* Config header and parity byte 2 */
2388c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
2398c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	new_value = 0x1b;
2428c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
2438c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_2_BIT)
2448c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_2_BIT));
2458c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
2468c2ecf20Sopenharmony_ci			value, parity_byte);
2478c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
2488c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	/* Config header and parity byte 3 */
2518c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
2528c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	new_value = (0x0 | (0x11 << 2));
2558c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
2568c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_3_BIT)
2578c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_3_BIT));
2588c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
2598c2ecf20Sopenharmony_ci			new_value, parity_byte);
2608c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
2618c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic void dp_audio_copy_management_sdp(struct dp_audio_private *audio)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
2678c2ecf20Sopenharmony_ci	u32 value, new_value;
2688c2ecf20Sopenharmony_ci	u8 parity_byte;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	/* Config header and parity byte 1 */
2718c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
2728c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	new_value = 0x05;
2758c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
2768c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_1_BIT)
2778c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_1_BIT));
2788c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
2798c2ecf20Sopenharmony_ci			value, parity_byte);
2808c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
2818c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	/* Config header and parity byte 2 */
2848c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
2858c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	new_value = 0x0F;
2888c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
2898c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_2_BIT)
2908c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_2_BIT));
2918c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
2928c2ecf20Sopenharmony_ci			value, parity_byte);
2938c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
2948c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Config header and parity byte 3 */
2978c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
2988c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	new_value = 0x0;
3018c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
3028c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_3_BIT)
3038c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_3_BIT));
3048c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 3: value = 0x%x, parity_byte = 0x%x\n",
3058c2ecf20Sopenharmony_ci			value, parity_byte);
3068c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
3078c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3);
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic void dp_audio_isrc_sdp(struct dp_audio_private *audio)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
3138c2ecf20Sopenharmony_ci	u32 value, new_value;
3148c2ecf20Sopenharmony_ci	u8 parity_byte;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	/* Config header and parity byte 1 */
3178c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
3188c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	new_value = 0x06;
3218c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
3228c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_1_BIT)
3238c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_1_BIT));
3248c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 1: value = 0x%x, parity_byte = 0x%x\n",
3258c2ecf20Sopenharmony_ci			value, parity_byte);
3268c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
3278c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* Config header and parity byte 2 */
3308c2ecf20Sopenharmony_ci	value = dp_audio_get_header(catalog,
3318c2ecf20Sopenharmony_ci			DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	new_value = 0x0F;
3348c2ecf20Sopenharmony_ci	parity_byte = dp_audio_calculate_parity(new_value);
3358c2ecf20Sopenharmony_ci	value |= ((new_value << HEADER_BYTE_2_BIT)
3368c2ecf20Sopenharmony_ci			| (parity_byte << PARITY_BYTE_2_BIT));
3378c2ecf20Sopenharmony_ci	DRM_DEBUG_DP("Header Byte 2: value = 0x%x, parity_byte = 0x%x\n",
3388c2ecf20Sopenharmony_ci			value, parity_byte);
3398c2ecf20Sopenharmony_ci	dp_audio_set_header(catalog, value,
3408c2ecf20Sopenharmony_ci		DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic void dp_audio_setup_sdp(struct dp_audio_private *audio)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	dp_catalog_audio_config_sdp(audio->catalog);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	dp_audio_stream_sdp(audio);
3488c2ecf20Sopenharmony_ci	dp_audio_timestamp_sdp(audio);
3498c2ecf20Sopenharmony_ci	dp_audio_infoframe_sdp(audio);
3508c2ecf20Sopenharmony_ci	dp_audio_copy_management_sdp(audio);
3518c2ecf20Sopenharmony_ci	dp_audio_isrc_sdp(audio);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic void dp_audio_setup_acr(struct dp_audio_private *audio)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	u32 select = 0;
3578c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	switch (audio->dp_audio.bw_code) {
3608c2ecf20Sopenharmony_ci	case DP_LINK_BW_1_62:
3618c2ecf20Sopenharmony_ci		select = 0;
3628c2ecf20Sopenharmony_ci		break;
3638c2ecf20Sopenharmony_ci	case DP_LINK_BW_2_7:
3648c2ecf20Sopenharmony_ci		select = 1;
3658c2ecf20Sopenharmony_ci		break;
3668c2ecf20Sopenharmony_ci	case DP_LINK_BW_5_4:
3678c2ecf20Sopenharmony_ci		select = 2;
3688c2ecf20Sopenharmony_ci		break;
3698c2ecf20Sopenharmony_ci	case DP_LINK_BW_8_1:
3708c2ecf20Sopenharmony_ci		select = 3;
3718c2ecf20Sopenharmony_ci		break;
3728c2ecf20Sopenharmony_ci	default:
3738c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("Unknown link rate\n");
3748c2ecf20Sopenharmony_ci		select = 0;
3758c2ecf20Sopenharmony_ci		break;
3768c2ecf20Sopenharmony_ci	}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	catalog->audio_data = select;
3798c2ecf20Sopenharmony_ci	dp_catalog_audio_config_acr(catalog);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void dp_audio_safe_to_exit_level(struct dp_audio_private *audio)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
3858c2ecf20Sopenharmony_ci	u32 safe_to_exit_level = 0;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	switch (audio->dp_audio.lane_count) {
3888c2ecf20Sopenharmony_ci	case 1:
3898c2ecf20Sopenharmony_ci		safe_to_exit_level = 14;
3908c2ecf20Sopenharmony_ci		break;
3918c2ecf20Sopenharmony_ci	case 2:
3928c2ecf20Sopenharmony_ci		safe_to_exit_level = 8;
3938c2ecf20Sopenharmony_ci		break;
3948c2ecf20Sopenharmony_ci	case 4:
3958c2ecf20Sopenharmony_ci		safe_to_exit_level = 5;
3968c2ecf20Sopenharmony_ci		break;
3978c2ecf20Sopenharmony_ci	default:
3988c2ecf20Sopenharmony_ci		DRM_DEBUG_DP("setting the default safe_to_exit_level = %u\n",
3998c2ecf20Sopenharmony_ci				safe_to_exit_level);
4008c2ecf20Sopenharmony_ci		safe_to_exit_level = 14;
4018c2ecf20Sopenharmony_ci		break;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	catalog->audio_data = safe_to_exit_level;
4058c2ecf20Sopenharmony_ci	dp_catalog_audio_sfe_level(catalog);
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic void dp_audio_enable(struct dp_audio_private *audio, bool enable)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct dp_catalog *catalog = audio->catalog;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	catalog->audio_data = enable;
4138c2ecf20Sopenharmony_ci	dp_catalog_audio_enable(catalog);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	audio->engine_on = enable;
4168c2ecf20Sopenharmony_ci}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_cistatic struct dp_audio_private *dp_audio_get_data(struct platform_device *pdev)
4198c2ecf20Sopenharmony_ci{
4208c2ecf20Sopenharmony_ci	struct dp_audio *dp_audio;
4218c2ecf20Sopenharmony_ci	struct msm_dp *dp_display;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	if (!pdev) {
4248c2ecf20Sopenharmony_ci		DRM_ERROR("invalid input\n");
4258c2ecf20Sopenharmony_ci		return ERR_PTR(-ENODEV);
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	dp_display = platform_get_drvdata(pdev);
4298c2ecf20Sopenharmony_ci	if (!dp_display) {
4308c2ecf20Sopenharmony_ci		DRM_ERROR("invalid input\n");
4318c2ecf20Sopenharmony_ci		return ERR_PTR(-ENODEV);
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	dp_audio = dp_display->dp_audio;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (!dp_audio) {
4378c2ecf20Sopenharmony_ci		DRM_ERROR("invalid dp_audio data\n");
4388c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return container_of(dp_audio, struct dp_audio_private, dp_audio);
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic int dp_audio_hook_plugged_cb(struct device *dev, void *data,
4458c2ecf20Sopenharmony_ci		hdmi_codec_plugged_cb fn,
4468c2ecf20Sopenharmony_ci		struct device *codec_dev)
4478c2ecf20Sopenharmony_ci{
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	struct platform_device *pdev;
4508c2ecf20Sopenharmony_ci	struct msm_dp *dp_display;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	pdev = to_platform_device(dev);
4538c2ecf20Sopenharmony_ci	if (!pdev) {
4548c2ecf20Sopenharmony_ci		pr_err("invalid input\n");
4558c2ecf20Sopenharmony_ci		return -ENODEV;
4568c2ecf20Sopenharmony_ci	}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	dp_display = platform_get_drvdata(pdev);
4598c2ecf20Sopenharmony_ci	if (!dp_display) {
4608c2ecf20Sopenharmony_ci		pr_err("invalid input\n");
4618c2ecf20Sopenharmony_ci		return -ENODEV;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	return dp_display_set_plugged_cb(dp_display, fn, codec_dev);
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic int dp_audio_get_eld(struct device *dev,
4688c2ecf20Sopenharmony_ci	void *data, uint8_t *buf, size_t len)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	struct platform_device *pdev;
4718c2ecf20Sopenharmony_ci	struct msm_dp *dp_display;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	pdev = to_platform_device(dev);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (!pdev) {
4768c2ecf20Sopenharmony_ci		DRM_ERROR("invalid input\n");
4778c2ecf20Sopenharmony_ci		return -ENODEV;
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	dp_display = platform_get_drvdata(pdev);
4818c2ecf20Sopenharmony_ci	if (!dp_display) {
4828c2ecf20Sopenharmony_ci		DRM_ERROR("invalid input\n");
4838c2ecf20Sopenharmony_ci		return -ENODEV;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	memcpy(buf, dp_display->connector->eld,
4878c2ecf20Sopenharmony_ci		min(sizeof(dp_display->connector->eld), len));
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	return 0;
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ciint dp_audio_hw_params(struct device *dev,
4938c2ecf20Sopenharmony_ci	void *data,
4948c2ecf20Sopenharmony_ci	struct hdmi_codec_daifmt *daifmt,
4958c2ecf20Sopenharmony_ci	struct hdmi_codec_params *params)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	int rc = 0;
4988c2ecf20Sopenharmony_ci	struct dp_audio_private *audio;
4998c2ecf20Sopenharmony_ci	struct platform_device *pdev;
5008c2ecf20Sopenharmony_ci	struct msm_dp *dp_display;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	pdev = to_platform_device(dev);
5038c2ecf20Sopenharmony_ci	dp_display = platform_get_drvdata(pdev);
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/*
5068c2ecf20Sopenharmony_ci	 * there could be cases where sound card can be opened even
5078c2ecf20Sopenharmony_ci	 * before OR even when DP is not connected . This can cause
5088c2ecf20Sopenharmony_ci	 * unclocked access as the audio subsystem relies on the DP
5098c2ecf20Sopenharmony_ci	 * driver to maintain the correct state of clocks. To protect
5108c2ecf20Sopenharmony_ci	 * such cases check for connection status and bail out if not
5118c2ecf20Sopenharmony_ci	 * connected.
5128c2ecf20Sopenharmony_ci	 */
5138c2ecf20Sopenharmony_ci	if (!dp_display->power_on) {
5148c2ecf20Sopenharmony_ci		rc = -EINVAL;
5158c2ecf20Sopenharmony_ci		goto end;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	audio = dp_audio_get_data(pdev);
5198c2ecf20Sopenharmony_ci	if (IS_ERR(audio)) {
5208c2ecf20Sopenharmony_ci		rc = PTR_ERR(audio);
5218c2ecf20Sopenharmony_ci		goto end;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	audio->channels = params->channels;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	dp_audio_setup_sdp(audio);
5278c2ecf20Sopenharmony_ci	dp_audio_setup_acr(audio);
5288c2ecf20Sopenharmony_ci	dp_audio_safe_to_exit_level(audio);
5298c2ecf20Sopenharmony_ci	dp_audio_enable(audio, true);
5308c2ecf20Sopenharmony_ci	dp_display_signal_audio_start(dp_display);
5318c2ecf20Sopenharmony_ci	dp_display->audio_enabled = true;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ciend:
5348c2ecf20Sopenharmony_ci	return rc;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic void dp_audio_shutdown(struct device *dev, void *data)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct dp_audio_private *audio;
5408c2ecf20Sopenharmony_ci	struct platform_device *pdev;
5418c2ecf20Sopenharmony_ci	struct msm_dp *dp_display;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	pdev = to_platform_device(dev);
5448c2ecf20Sopenharmony_ci	dp_display = platform_get_drvdata(pdev);
5458c2ecf20Sopenharmony_ci	audio = dp_audio_get_data(pdev);
5468c2ecf20Sopenharmony_ci	if (IS_ERR(audio)) {
5478c2ecf20Sopenharmony_ci		DRM_ERROR("failed to get audio data\n");
5488c2ecf20Sopenharmony_ci		return;
5498c2ecf20Sopenharmony_ci	}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/*
5528c2ecf20Sopenharmony_ci	 * if audio was not enabled there is no need
5538c2ecf20Sopenharmony_ci	 * to execute the shutdown and we can bail out early.
5548c2ecf20Sopenharmony_ci	 * This also makes sure that we dont cause an unclocked
5558c2ecf20Sopenharmony_ci	 * access when audio subsystem calls this without DP being
5568c2ecf20Sopenharmony_ci	 * connected. is_connected cannot be used here as its set
5578c2ecf20Sopenharmony_ci	 * to false earlier than this call
5588c2ecf20Sopenharmony_ci	 */
5598c2ecf20Sopenharmony_ci	if (!dp_display->audio_enabled)
5608c2ecf20Sopenharmony_ci		return;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	dp_audio_enable(audio, false);
5638c2ecf20Sopenharmony_ci	/* signal the dp display to safely shutdown clocks */
5648c2ecf20Sopenharmony_ci	dp_display_signal_audio_complete(dp_display);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic const struct hdmi_codec_ops dp_audio_codec_ops = {
5688c2ecf20Sopenharmony_ci	.hw_params = dp_audio_hw_params,
5698c2ecf20Sopenharmony_ci	.audio_shutdown = dp_audio_shutdown,
5708c2ecf20Sopenharmony_ci	.get_eld = dp_audio_get_eld,
5718c2ecf20Sopenharmony_ci	.hook_plugged_cb = dp_audio_hook_plugged_cb,
5728c2ecf20Sopenharmony_ci};
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic struct hdmi_codec_pdata codec_data = {
5758c2ecf20Sopenharmony_ci	.ops = &dp_audio_codec_ops,
5768c2ecf20Sopenharmony_ci	.max_i2s_channels = 8,
5778c2ecf20Sopenharmony_ci	.i2s = 1,
5788c2ecf20Sopenharmony_ci};
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_civoid dp_unregister_audio_driver(struct device *dev, struct dp_audio *dp_audio)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct dp_audio_private *audio_priv;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	audio_priv = container_of(dp_audio, struct dp_audio_private, dp_audio);
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	if (audio_priv->audio_pdev) {
5878c2ecf20Sopenharmony_ci		platform_device_unregister(audio_priv->audio_pdev);
5888c2ecf20Sopenharmony_ci		audio_priv->audio_pdev = NULL;
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ciint dp_register_audio_driver(struct device *dev,
5938c2ecf20Sopenharmony_ci		struct dp_audio *dp_audio)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	struct dp_audio_private *audio_priv;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	audio_priv = container_of(dp_audio,
5988c2ecf20Sopenharmony_ci			struct dp_audio_private, dp_audio);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	audio_priv->audio_pdev = platform_device_register_data(dev,
6018c2ecf20Sopenharmony_ci						HDMI_CODEC_DRV_NAME,
6028c2ecf20Sopenharmony_ci						PLATFORM_DEVID_AUTO,
6038c2ecf20Sopenharmony_ci						&codec_data,
6048c2ecf20Sopenharmony_ci						sizeof(codec_data));
6058c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(audio_priv->audio_pdev);
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cistruct dp_audio *dp_audio_get(struct platform_device *pdev,
6098c2ecf20Sopenharmony_ci			struct dp_panel *panel,
6108c2ecf20Sopenharmony_ci			struct dp_catalog *catalog)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	int rc = 0;
6138c2ecf20Sopenharmony_ci	struct dp_audio_private *audio;
6148c2ecf20Sopenharmony_ci	struct dp_audio *dp_audio;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (!pdev || !panel || !catalog) {
6178c2ecf20Sopenharmony_ci		DRM_ERROR("invalid input\n");
6188c2ecf20Sopenharmony_ci		rc = -EINVAL;
6198c2ecf20Sopenharmony_ci		goto error;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL);
6238c2ecf20Sopenharmony_ci	if (!audio) {
6248c2ecf20Sopenharmony_ci		rc = -ENOMEM;
6258c2ecf20Sopenharmony_ci		goto error;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	audio->pdev = pdev;
6298c2ecf20Sopenharmony_ci	audio->panel = panel;
6308c2ecf20Sopenharmony_ci	audio->catalog = catalog;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	dp_audio = &audio->dp_audio;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	dp_catalog_audio_init(catalog);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	return dp_audio;
6378c2ecf20Sopenharmony_cierror:
6388c2ecf20Sopenharmony_ci	return ERR_PTR(rc);
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_civoid dp_audio_put(struct dp_audio *dp_audio)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct dp_audio_private *audio;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	if (!dp_audio)
6468c2ecf20Sopenharmony_ci		return;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	devm_kfree(&audio->pdev->dev, audio);
6518c2ecf20Sopenharmony_ci}
652