xref: /linux/sound/soc/sdca/sdca_device.c (revision b61104e7a6349bd2c2b3e2fb3260d87f15eda8f4)
1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2 // Copyright(c) 2024 Intel Corporation
3 
4 /*
5  * The MIPI SDCA specification is available for public downloads at
6  * https://www.mipi.org/mipi-sdca-v1-0-download
7  */
8 
9 #include <linux/acpi.h>
10 #include <linux/device.h>
11 #include <linux/dmi.h>
12 #include <linux/module.h>
13 #include <linux/property.h>
14 #include <linux/soundwire/sdw.h>
15 #include <sound/sdca.h>
16 #include <sound/sdca_function.h>
17 
18 void sdca_lookup_interface_revision(struct sdw_slave *slave)
19 {
20 	struct fwnode_handle *fwnode = slave->dev.fwnode;
21 
22 	/*
23 	 * if this property is not present, then the sdca_interface_revision will
24 	 * remain zero, which will be considered as 'not defined' or 'invalid'.
25 	 */
26 	fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision",
27 				 &slave->sdca_data.interface_revision);
28 }
29 EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, "SND_SOC_SDCA");
30 
31 static void devm_acpi_table_put(void *ptr)
32 {
33 	acpi_put_table((struct acpi_table_header *)ptr);
34 }
35 
36 void sdca_lookup_swft(struct sdw_slave *slave)
37 {
38 	acpi_status status;
39 
40 	status = acpi_get_table(ACPI_SIG_SWFT, 0,
41 				(struct acpi_table_header **)&slave->sdca_data.swft);
42 	if (ACPI_FAILURE(status))
43 		dev_info(&slave->dev, "SWFT not available\n");
44 	else
45 		devm_add_action_or_reset(&slave->dev, devm_acpi_table_put,
46 					 &slave->sdca_data.swft);
47 }
48 EXPORT_SYMBOL_NS(sdca_lookup_swft, "SND_SOC_SDCA");
49 
50 static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave)
51 {
52 	struct sdw_slave_id *id = &slave->id;
53 	int i;
54 
55 	/*
56 	 * The RT712_VA relies on the v06r04 draft, and the
57 	 * RT712_VB on a more recent v08r01 draft.
58 	 */
59 	if (slave->sdca_data.interface_revision < 0x0801)
60 		return false;
61 
62 	if (id->mfg_id != 0x025d)
63 		return false;
64 
65 	if (id->part_id != 0x712 &&
66 	    id->part_id != 0x713 &&
67 	    id->part_id != 0x716 &&
68 	    id->part_id != 0x717)
69 		return false;
70 
71 	for (i = 0; i < slave->sdca_data.num_functions; i++) {
72 		if (slave->sdca_data.function[i].type == SDCA_FUNCTION_TYPE_SMART_MIC)
73 			return true;
74 	}
75 
76 	return false;
77 }
78 
79 static bool sdca_device_quirk_skip_func_type_patching(struct sdw_slave *slave)
80 {
81 	const char *vendor, *sku;
82 
83 	vendor = dmi_get_system_info(DMI_SYS_VENDOR);
84 	sku = dmi_get_system_info(DMI_PRODUCT_SKU);
85 
86 	if (vendor && sku &&
87 	    !strcmp(vendor, "Dell Inc.") &&
88 	    (!strcmp(sku, "0C62") || !strcmp(sku, "0C63") || !strcmp(sku, "0C6B")) &&
89 	    slave->sdca_data.interface_revision == 0x061c &&
90 	    slave->id.mfg_id == 0x01fa && slave->id.part_id == 0x4243)
91 		return true;
92 
93 	return false;
94 }
95 
96 bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
97 {
98 	switch (quirk) {
99 	case SDCA_QUIRKS_RT712_VB:
100 		return sdca_device_quirk_rt712_vb(slave);
101 	case SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING:
102 		return sdca_device_quirk_skip_func_type_patching(slave);
103 	default:
104 		break;
105 	}
106 	return false;
107 }
108 EXPORT_SYMBOL_NS(sdca_device_quirk_match, "SND_SOC_SDCA");
109