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