Linux Audio

Check our new training course

Yocto / OpenEmbedded training

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