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/dmi.h>
11 #include <linux/module.h>
12 #include <linux/property.h>
13 #include <linux/soundwire/sdw.h>
14 #include <sound/sdca.h>
15 #include <sound/sdca_function.h>
16
sdca_lookup_interface_revision(struct sdw_slave * slave)17 void sdca_lookup_interface_revision(struct sdw_slave *slave)
18 {
19 struct fwnode_handle *fwnode = slave->dev.fwnode;
20
21 /*
22 * if this property is not present, then the sdca_interface_revision will
23 * remain zero, which will be considered as 'not defined' or 'invalid'.
24 */
25 fwnode_property_read_u32(fwnode, "mipi-sdw-sdca-interface-revision",
26 &slave->sdca_data.interface_revision);
27 }
28 EXPORT_SYMBOL_NS(sdca_lookup_interface_revision, "SND_SOC_SDCA");
29
sdca_device_quirk_rt712_vb(struct sdw_slave * slave)30 static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave)
31 {
32 struct sdw_slave_id *id = &slave->id;
33 int i;
34
35 /*
36 * The RT712_VA relies on the v06r04 draft, and the
37 * RT712_VB on a more recent v08r01 draft.
38 */
39 if (slave->sdca_data.interface_revision < 0x0801)
40 return false;
41
42 if (id->mfg_id != 0x025d)
43 return false;
44
45 if (id->part_id != 0x712 &&
46 id->part_id != 0x713 &&
47 id->part_id != 0x716 &&
48 id->part_id != 0x717)
49 return false;
50
51 for (i = 0; i < slave->sdca_data.num_functions; i++) {
52 if (slave->sdca_data.function[i].type == SDCA_FUNCTION_TYPE_SMART_MIC)
53 return true;
54 }
55
56 return false;
57 }
58
sdca_device_quirk_skip_func_type_patching(struct sdw_slave * slave)59 static bool sdca_device_quirk_skip_func_type_patching(struct sdw_slave *slave)
60 {
61 const char *vendor, *sku;
62
63 vendor = dmi_get_system_info(DMI_SYS_VENDOR);
64 sku = dmi_get_system_info(DMI_PRODUCT_SKU);
65
66 if (vendor && sku &&
67 !strcmp(vendor, "Dell Inc.") &&
68 (!strcmp(sku, "0C62") || !strcmp(sku, "0C63") || !strcmp(sku, "0C6B")) &&
69 slave->sdca_data.interface_revision == 0x061c &&
70 slave->id.mfg_id == 0x01fa && slave->id.part_id == 0x4243)
71 return true;
72
73 return false;
74 }
75
sdca_device_quirk_match(struct sdw_slave * slave,enum sdca_quirk quirk)76 bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk)
77 {
78 switch (quirk) {
79 case SDCA_QUIRKS_RT712_VB:
80 return sdca_device_quirk_rt712_vb(slave);
81 case SDCA_QUIRKS_SKIP_FUNC_TYPE_PATCHING:
82 return sdca_device_quirk_skip_func_type_patching(slave);
83 default:
84 break;
85 }
86 return false;
87 }
88 EXPORT_SYMBOL_NS(sdca_device_quirk_match, "SND_SOC_SDCA");
89