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