xref: /linux/sound/soc/sdca/sdca_functions.c (revision 3a513da1ae33972e59efeef7908061f1f24af480)
1*3a513da1SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2*3a513da1SPierre-Louis Bossart // Copyright(c) 2024 Intel Corporation
3*3a513da1SPierre-Louis Bossart 
4*3a513da1SPierre-Louis Bossart /*
5*3a513da1SPierre-Louis Bossart  * The MIPI SDCA specification is available for public downloads at
6*3a513da1SPierre-Louis Bossart  * https://www.mipi.org/mipi-sdca-v1-0-download
7*3a513da1SPierre-Louis Bossart  */
8*3a513da1SPierre-Louis Bossart 
9*3a513da1SPierre-Louis Bossart #include <linux/acpi.h>
10*3a513da1SPierre-Louis Bossart #include <linux/soundwire/sdw.h>
11*3a513da1SPierre-Louis Bossart #include <sound/sdca.h>
12*3a513da1SPierre-Louis Bossart #include <sound/sdca_function.h>
13*3a513da1SPierre-Louis Bossart 
14*3a513da1SPierre-Louis Bossart static int patch_sdca_function_type(struct device *dev,
15*3a513da1SPierre-Louis Bossart 				    u32 interface_revision,
16*3a513da1SPierre-Louis Bossart 				    u32 *function_type,
17*3a513da1SPierre-Louis Bossart 				    const char **function_name)
18*3a513da1SPierre-Louis Bossart {
19*3a513da1SPierre-Louis Bossart 	unsigned long function_type_patch = 0;
20*3a513da1SPierre-Louis Bossart 
21*3a513da1SPierre-Louis Bossart 	/*
22*3a513da1SPierre-Louis Bossart 	 * Unfortunately early SDCA specifications used different indices for Functions,
23*3a513da1SPierre-Louis Bossart 	 * for backwards compatibility we have to reorder the values found
24*3a513da1SPierre-Louis Bossart 	 */
25*3a513da1SPierre-Louis Bossart 	if (interface_revision >= 0x0801)
26*3a513da1SPierre-Louis Bossart 		goto skip_early_draft_order;
27*3a513da1SPierre-Louis Bossart 
28*3a513da1SPierre-Louis Bossart 	switch (*function_type) {
29*3a513da1SPierre-Louis Bossart 	case 1:
30*3a513da1SPierre-Louis Bossart 		function_type_patch = SDCA_FUNCTION_TYPE_SMART_AMP;
31*3a513da1SPierre-Louis Bossart 		break;
32*3a513da1SPierre-Louis Bossart 	case 2:
33*3a513da1SPierre-Louis Bossart 		function_type_patch = SDCA_FUNCTION_TYPE_SMART_MIC;
34*3a513da1SPierre-Louis Bossart 		break;
35*3a513da1SPierre-Louis Bossart 	case 3:
36*3a513da1SPierre-Louis Bossart 		function_type_patch = SDCA_FUNCTION_TYPE_SPEAKER_MIC;
37*3a513da1SPierre-Louis Bossart 		break;
38*3a513da1SPierre-Louis Bossart 	case 4:
39*3a513da1SPierre-Louis Bossart 		function_type_patch = SDCA_FUNCTION_TYPE_UAJ;
40*3a513da1SPierre-Louis Bossart 		break;
41*3a513da1SPierre-Louis Bossart 	case 5:
42*3a513da1SPierre-Louis Bossart 		function_type_patch = SDCA_FUNCTION_TYPE_RJ;
43*3a513da1SPierre-Louis Bossart 		break;
44*3a513da1SPierre-Louis Bossart 	case 6:
45*3a513da1SPierre-Louis Bossart 		function_type_patch = SDCA_FUNCTION_TYPE_HID;
46*3a513da1SPierre-Louis Bossart 		break;
47*3a513da1SPierre-Louis Bossart 	default:
48*3a513da1SPierre-Louis Bossart 		dev_warn(dev, "%s: SDCA version %#x unsupported function type %d, skipped\n",
49*3a513da1SPierre-Louis Bossart 			 __func__, interface_revision, *function_type);
50*3a513da1SPierre-Louis Bossart 		return -EINVAL;
51*3a513da1SPierre-Louis Bossart 	}
52*3a513da1SPierre-Louis Bossart 
53*3a513da1SPierre-Louis Bossart skip_early_draft_order:
54*3a513da1SPierre-Louis Bossart 	if (function_type_patch)
55*3a513da1SPierre-Louis Bossart 		*function_type = function_type_patch;
56*3a513da1SPierre-Louis Bossart 
57*3a513da1SPierre-Louis Bossart 	/* now double-check the values */
58*3a513da1SPierre-Louis Bossart 	switch (*function_type) {
59*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_SMART_AMP:
60*3a513da1SPierre-Louis Bossart 		*function_name = SDCA_FUNCTION_TYPE_SMART_AMP_NAME;
61*3a513da1SPierre-Louis Bossart 		break;
62*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_SMART_MIC:
63*3a513da1SPierre-Louis Bossart 		*function_name = SDCA_FUNCTION_TYPE_SMART_MIC_NAME;
64*3a513da1SPierre-Louis Bossart 		break;
65*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_UAJ:
66*3a513da1SPierre-Louis Bossart 		*function_name = SDCA_FUNCTION_TYPE_UAJ_NAME;
67*3a513da1SPierre-Louis Bossart 		break;
68*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_HID:
69*3a513da1SPierre-Louis Bossart 		*function_name = SDCA_FUNCTION_TYPE_HID_NAME;
70*3a513da1SPierre-Louis Bossart 		break;
71*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_SIMPLE_AMP:
72*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_SIMPLE_MIC:
73*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_SPEAKER_MIC:
74*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_RJ:
75*3a513da1SPierre-Louis Bossart 	case SDCA_FUNCTION_TYPE_IMP_DEF:
76*3a513da1SPierre-Louis Bossart 		dev_warn(dev, "%s: found unsupported SDCA function type %d, skipped\n",
77*3a513da1SPierre-Louis Bossart 			 __func__, *function_type);
78*3a513da1SPierre-Louis Bossart 		return -EINVAL;
79*3a513da1SPierre-Louis Bossart 	default:
80*3a513da1SPierre-Louis Bossart 		dev_err(dev, "%s: found invalid SDCA function type %d, skipped\n",
81*3a513da1SPierre-Louis Bossart 			__func__, *function_type);
82*3a513da1SPierre-Louis Bossart 		return -EINVAL;
83*3a513da1SPierre-Louis Bossart 	}
84*3a513da1SPierre-Louis Bossart 
85*3a513da1SPierre-Louis Bossart 	dev_info(dev, "%s: found SDCA function %s (type %d)\n",
86*3a513da1SPierre-Louis Bossart 		 __func__, *function_name, *function_type);
87*3a513da1SPierre-Louis Bossart 
88*3a513da1SPierre-Louis Bossart 	return 0;
89*3a513da1SPierre-Louis Bossart }
90*3a513da1SPierre-Louis Bossart 
91*3a513da1SPierre-Louis Bossart static int find_sdca_function(struct acpi_device *adev, void *data)
92*3a513da1SPierre-Louis Bossart {
93*3a513da1SPierre-Louis Bossart 	struct fwnode_handle *function_node = acpi_fwnode_handle(adev);
94*3a513da1SPierre-Louis Bossart 	struct sdca_device_data *sdca_data = data;
95*3a513da1SPierre-Louis Bossart 	struct device *dev = &adev->dev;
96*3a513da1SPierre-Louis Bossart 	struct fwnode_handle *control5; /* used to identify function type */
97*3a513da1SPierre-Louis Bossart 	const char *function_name;
98*3a513da1SPierre-Louis Bossart 	u32 function_type;
99*3a513da1SPierre-Louis Bossart 	int func_index;
100*3a513da1SPierre-Louis Bossart 	u64 addr;
101*3a513da1SPierre-Louis Bossart 	int ret;
102*3a513da1SPierre-Louis Bossart 
103*3a513da1SPierre-Louis Bossart 	if (sdca_data->num_functions >= SDCA_MAX_FUNCTION_COUNT) {
104*3a513da1SPierre-Louis Bossart 		dev_err(dev, "%s: maximum number of functions exceeded\n", __func__);
105*3a513da1SPierre-Louis Bossart 		return -EINVAL;
106*3a513da1SPierre-Louis Bossart 	}
107*3a513da1SPierre-Louis Bossart 
108*3a513da1SPierre-Louis Bossart 	/*
109*3a513da1SPierre-Louis Bossart 	 * The number of functions cannot exceed 8, we could use
110*3a513da1SPierre-Louis Bossart 	 * acpi_get_local_address() but the value is stored as u64 so
111*3a513da1SPierre-Louis Bossart 	 * we might as well avoid casts and intermediate levels
112*3a513da1SPierre-Louis Bossart 	 */
113*3a513da1SPierre-Louis Bossart 	ret = acpi_get_local_u64_address(adev->handle, &addr);
114*3a513da1SPierre-Louis Bossart 	if (ret < 0)
115*3a513da1SPierre-Louis Bossart 		return ret;
116*3a513da1SPierre-Louis Bossart 
117*3a513da1SPierre-Louis Bossart 	if (!addr) {
118*3a513da1SPierre-Louis Bossart 		dev_err(dev, "%s: no addr\n", __func__);
119*3a513da1SPierre-Louis Bossart 		return -ENODEV;
120*3a513da1SPierre-Louis Bossart 	}
121*3a513da1SPierre-Louis Bossart 
122*3a513da1SPierre-Louis Bossart 	/*
123*3a513da1SPierre-Louis Bossart 	 * Extracting the topology type for an SDCA function is a
124*3a513da1SPierre-Louis Bossart 	 * convoluted process.
125*3a513da1SPierre-Louis Bossart 	 * The Function type is only visible as a result of a read
126*3a513da1SPierre-Louis Bossart 	 * from a control. In theory this would mean reading from the hardware,
127*3a513da1SPierre-Louis Bossart 	 * but the SDCA/DisCo specs defined the notion of "DC value" - a constant
128*3a513da1SPierre-Louis Bossart 	 * represented with a DSD subproperty.
129*3a513da1SPierre-Louis Bossart 	 * Drivers have to query the properties for the control
130*3a513da1SPierre-Louis Bossart 	 * SDCA_CONTROL_ENTITY_0_FUNCTION_TOPOLOGY (0x05)
131*3a513da1SPierre-Louis Bossart 	 */
132*3a513da1SPierre-Louis Bossart 	control5 = fwnode_get_named_child_node(function_node,
133*3a513da1SPierre-Louis Bossart 					       "mipi-sdca-control-0x5-subproperties");
134*3a513da1SPierre-Louis Bossart 	if (!control5)
135*3a513da1SPierre-Louis Bossart 		return -ENODEV;
136*3a513da1SPierre-Louis Bossart 
137*3a513da1SPierre-Louis Bossart 	ret = fwnode_property_read_u32(control5, "mipi-sdca-control-dc-value",
138*3a513da1SPierre-Louis Bossart 				       &function_type);
139*3a513da1SPierre-Louis Bossart 
140*3a513da1SPierre-Louis Bossart 	fwnode_handle_put(control5);
141*3a513da1SPierre-Louis Bossart 
142*3a513da1SPierre-Louis Bossart 	if (ret < 0) {
143*3a513da1SPierre-Louis Bossart 		dev_err(dev, "%s: the function type can only be determined from ACPI information\n",
144*3a513da1SPierre-Louis Bossart 			__func__);
145*3a513da1SPierre-Louis Bossart 		return ret;
146*3a513da1SPierre-Louis Bossart 	}
147*3a513da1SPierre-Louis Bossart 
148*3a513da1SPierre-Louis Bossart 	ret = patch_sdca_function_type(dev, sdca_data->interface_revision,
149*3a513da1SPierre-Louis Bossart 				       &function_type, &function_name);
150*3a513da1SPierre-Louis Bossart 	if (ret < 0)
151*3a513da1SPierre-Louis Bossart 		return ret;
152*3a513da1SPierre-Louis Bossart 
153*3a513da1SPierre-Louis Bossart 	/* store results */
154*3a513da1SPierre-Louis Bossart 	func_index = sdca_data->num_functions;
155*3a513da1SPierre-Louis Bossart 	sdca_data->sdca_func[func_index].adr = addr;
156*3a513da1SPierre-Louis Bossart 	sdca_data->sdca_func[func_index].type = function_type;
157*3a513da1SPierre-Louis Bossart 	sdca_data->sdca_func[func_index].name = function_name;
158*3a513da1SPierre-Louis Bossart 	sdca_data->num_functions++;
159*3a513da1SPierre-Louis Bossart 
160*3a513da1SPierre-Louis Bossart 	return 0;
161*3a513da1SPierre-Louis Bossart }
162*3a513da1SPierre-Louis Bossart 
163*3a513da1SPierre-Louis Bossart void sdca_lookup_functions(struct sdw_slave *slave)
164*3a513da1SPierre-Louis Bossart {
165*3a513da1SPierre-Louis Bossart 	struct device *dev = &slave->dev;
166*3a513da1SPierre-Louis Bossart 	struct acpi_device *adev = to_acpi_device_node(dev->fwnode);
167*3a513da1SPierre-Louis Bossart 
168*3a513da1SPierre-Louis Bossart 	acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data);
169*3a513da1SPierre-Louis Bossart }
170*3a513da1SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdca_lookup_functions, SND_SOC_SDCA);
171*3a513da1SPierre-Louis Bossart 
172*3a513da1SPierre-Louis Bossart MODULE_LICENSE("Dual BSD/GPL");
173*3a513da1SPierre-Louis Bossart MODULE_DESCRIPTION("SDCA library");
174