diff options
Diffstat (limited to 'sound/soc/sdca/sdca_functions.c')
| -rw-r--r-- | sound/soc/sdca/sdca_functions.c | 310 |
1 files changed, 275 insertions, 35 deletions
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 0ccb6775f4de..5a1f120487ef 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -6,8 +6,6 @@ * https://www.mipi.org/mipi-sdca-v1-0-download */ -#define dev_fmt(fmt) "%s: " fmt, __func__ - #include <linux/acpi.h> #include <linux/byteorder/generic.h> #include <linux/cleanup.h> @@ -16,6 +14,7 @@ #include <linux/module.h> #include <linux/property.h> #include <linux/soundwire/sdw.h> +#include <linux/string.h> #include <linux/types.h> #include <sound/sdca.h> #include <sound/sdca_function.h> @@ -79,6 +78,8 @@ static const char *get_sdca_function_name(u32 function_type) return SDCA_FUNCTION_TYPE_SPEAKER_MIC_NAME; case SDCA_FUNCTION_TYPE_RJ: return SDCA_FUNCTION_TYPE_RJ_NAME; + case SDCA_FUNCTION_TYPE_COMPANION_AMP: + return SDCA_FUNCTION_TYPE_COMPANION_AMP_NAME; case SDCA_FUNCTION_TYPE_IMP_DEF: return SDCA_FUNCTION_TYPE_IMP_DEF_NAME; default: @@ -179,11 +180,11 @@ static int find_sdca_function(struct acpi_device *adev, void *data) */ void sdca_lookup_functions(struct sdw_slave *slave) { - struct device *dev = &slave->dev; - struct acpi_device *adev = to_acpi_device_node(dev->fwnode); + struct device *sdev = &slave->dev; + struct acpi_device *adev = to_acpi_device_node(sdev->fwnode); if (!adev) { - dev_info(dev, "no matching ACPI device found, ignoring peripheral\n"); + dev_info(sdev, "no matching ACPI device found, ignoring peripheral\n"); return; } @@ -779,6 +780,62 @@ find_sdca_control_datatype(const struct sdca_entity *entity, } } +static bool find_sdca_control_volatile(const struct sdca_entity *entity, + const struct sdca_control *control) +{ + switch (control->mode) { + case SDCA_ACCESS_MODE_DC: + return false; + case SDCA_ACCESS_MODE_RO: + case SDCA_ACCESS_MODE_RW1S: + case SDCA_ACCESS_MODE_RW1C: + return true; + default: + break; + } + + switch (SDCA_CTL_TYPE(entity->type, control->sel)) { + case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER): + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(XU, FDL_STATUS): + case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER): + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH): + return true; + default: + return false; + } +} + static int find_sdca_control_range(struct device *dev, struct fwnode_handle *control_node, struct sdca_control_range *range) @@ -931,6 +988,8 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti break; } + control->is_volatile = find_sdca_control_volatile(entity, control); + ret = find_sdca_control_range(dev, control_node, &control->range); if (ret) { dev_err(dev, "%s: control %#x: range missing: %d\n", @@ -953,10 +1012,10 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti control->type = find_sdca_control_datatype(entity, control); control->nbits = find_sdca_control_bits(entity, control); - dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n", - entity->label, control->label, control->sel, - control->mode, control->layers, control->cn_list, - control->interrupt_position, control->deferrable ? "deferrable" : ""); + dev_dbg(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d %s\n", + entity->label, control->label, control->sel, + control->mode, control->layers, control->cn_list, + control->interrupt_position, control->deferrable ? "deferrable" : ""); return 0; } @@ -1062,6 +1121,14 @@ static int find_sdca_entity_iot(struct device *dev, terminal->type = tmp; terminal->is_dataport = find_sdca_iot_dataport(terminal); + if (!terminal->is_dataport) { + const char *type_name = sdca_find_terminal_name(terminal->type); + + if (type_name) + entity->label = devm_kasprintf(dev, GFP_KERNEL, "%s %s", + entity->label, type_name); + } + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-terminal-reference-number", &tmp); if (!ret) @@ -1077,9 +1144,9 @@ static int find_sdca_entity_iot(struct device *dev, if (!ret) terminal->num_transducer = tmp; - dev_info(dev, "%s: terminal type %#x ref %#x conn %#x count %d\n", - entity->label, terminal->type, terminal->reference, - terminal->connector, terminal->num_transducer); + dev_dbg(dev, "%s: terminal type %#x ref %#x conn %#x count %d\n", + entity->label, terminal->type, terminal->reference, + terminal->connector, terminal->num_transducer); return 0; } @@ -1105,8 +1172,8 @@ static int find_sdca_entity_cs(struct device *dev, if (!ret) clock->max_delay = tmp; - dev_info(dev, "%s: clock type %#x delay %d\n", entity->label, - clock->type, clock->max_delay); + dev_dbg(dev, "%s: clock type %#x delay %d\n", entity->label, + clock->type, clock->max_delay); return 0; } @@ -1157,8 +1224,8 @@ static int find_sdca_entity_pde(struct device *dev, delays[i].to_ps = delay_list[j++]; delays[i].us = delay_list[j++]; - dev_info(dev, "%s: from %#x to %#x delay %dus\n", entity->label, - delays[i].from_ps, delays[i].to_ps, delays[i].us); + dev_dbg(dev, "%s: from %#x to %#x delay %dus\n", entity->label, + delays[i].from_ps, delays[i].to_ps, delays[i].us); } power->num_max_delay = num_delays; @@ -1254,7 +1321,8 @@ bad_list: } static int -find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node, +find_sdca_entity_hide(struct device *dev, struct sdw_slave *sdw, + struct fwnode_handle *function_node, struct fwnode_handle *entity_node, struct sdca_entity *entity) { struct sdca_entity_hide *hide = &entity->hide; @@ -1263,7 +1331,7 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node, unsigned char *report_desc = NULL; ret = fwnode_property_read_u32(entity_node, - "mipi-sdca-RxUMP-ownership-transition-maxdelay", &delay); + "mipi-sdca-RxUMP-ownership-transition-max-delay", &delay); if (!ret) hide->max_delay = delay; @@ -1329,7 +1397,7 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node, report_desc, nval); /* add HID device */ - ret = sdca_add_hid_device(dev, entity); + ret = sdca_add_hid_device(dev, sdw, entity); if (ret) { dev_err(dev, "%pfwP: failed to add HID device: %d\n", entity_node, ret); return ret; @@ -1340,7 +1408,29 @@ find_sdca_entity_hide(struct device *dev, struct fwnode_handle *function_node, return 0; } -static int find_sdca_entity(struct device *dev, +static int find_sdca_entity_xu(struct device *dev, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity_xu *xu = &entity->xu; + u32 tmp; + int ret; + + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-RxUMP-ownership-transition-max-delay", + &tmp); + if (!ret) + xu->max_delay = tmp; + + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-FDL-reset-mechanism", + &tmp); + if (!ret) + xu->reset_mechanism = tmp; + + return 0; +} + +static int find_sdca_entity(struct device *dev, struct sdw_slave *sdw, struct fwnode_handle *function_node, struct fwnode_handle *entity_node, struct sdca_entity *entity) @@ -1364,14 +1454,17 @@ static int find_sdca_entity(struct device *dev, entity->type = tmp; - dev_info(dev, "%s: entity %#x type %#x\n", - entity->label, entity->id, entity->type); + dev_dbg(dev, "%s: entity %#x type %#x\n", + entity->label, entity->id, entity->type); switch (entity->type) { case SDCA_ENTITY_TYPE_IT: case SDCA_ENTITY_TYPE_OT: ret = find_sdca_entity_iot(dev, entity_node, entity); break; + case SDCA_ENTITY_TYPE_XU: + ret = find_sdca_entity_xu(dev, entity_node, entity); + break; case SDCA_ENTITY_TYPE_CS: ret = find_sdca_entity_cs(dev, entity_node, entity); break; @@ -1382,7 +1475,8 @@ static int find_sdca_entity(struct device *dev, ret = find_sdca_entity_ge(dev, entity_node, entity); break; case SDCA_ENTITY_TYPE_HIDE: - ret = find_sdca_entity_hide(dev, function_node, entity_node, entity); + ret = find_sdca_entity_hide(dev, sdw, function_node, + entity_node, entity); break; default: break; @@ -1397,7 +1491,7 @@ static int find_sdca_entity(struct device *dev, return 0; } -static int find_sdca_entities(struct device *dev, +static int find_sdca_entities(struct device *dev, struct sdw_slave *sdw, struct fwnode_handle *function_node, struct sdca_function_data *function) { @@ -1449,7 +1543,8 @@ static int find_sdca_entities(struct device *dev, return -EINVAL; } - ret = find_sdca_entity(dev, function_node, entity_node, &entities[i]); + ret = find_sdca_entity(dev, sdw, function_node, + entity_node, &entities[i]); fwnode_handle_put(entity_node); if (ret) return ret; @@ -1479,7 +1574,7 @@ static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data * for (i = 0; i < function->num_entities; i++) { struct sdca_entity *entity = &function->entities[i]; - if (!strcmp(entity->label, entity_label)) + if (!strncmp(entity->label, entity_label, strlen(entity_label))) return entity; } @@ -1535,7 +1630,7 @@ static int find_sdca_entity_connection_iot(struct device *dev, terminal->clock = clock_entity; - dev_info(dev, "%s -> %s\n", clock_entity->label, entity->label); + dev_dbg(dev, "%s -> %s\n", clock_entity->label, entity->label); fwnode_handle_put(clock_node); return 0; @@ -1585,7 +1680,7 @@ static int find_sdca_entity_connection_pde(struct device *dev, return -EINVAL; } - dev_info(dev, "%s -> %s\n", managed[i]->label, entity->label); + dev_dbg(dev, "%s -> %s\n", managed[i]->label, entity->label); } power->num_managed = num_managed; @@ -1720,7 +1815,7 @@ static int find_sdca_entity_connection(struct device *dev, pins[i] = connected_entity; - dev_info(dev, "%s -> %s\n", connected_entity->label, entity->label); + dev_dbg(dev, "%s -> %s\n", connected_entity->label, entity->label); i++; fwnode_handle_put(connected_node); @@ -1805,8 +1900,8 @@ static int find_sdca_cluster_channel(struct device *dev, channel->relationship = tmp; - dev_info(dev, "cluster %#x: channel id %#x purpose %#x relationship %#x\n", - cluster->id, channel->id, channel->purpose, channel->relationship); + dev_dbg(dev, "cluster %#x: channel id %#x purpose %#x relationship %#x\n", + cluster->id, channel->id, channel->purpose, channel->relationship); return 0; } @@ -1925,15 +2020,105 @@ static int find_sdca_clusters(struct device *dev, return 0; } +static int find_sdca_filesets(struct device *dev, struct sdw_slave *sdw, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + static const int mult_fileset = 3; + char fileset_name[SDCA_PROPERTY_LENGTH]; + u32 *filesets_list __free(kfree) = NULL; + struct sdca_fdl_set *sets; + int num_sets; + int i, j; + + num_sets = fwnode_property_count_u32(function_node, + "mipi-sdca-file-set-id-list"); + if (num_sets == 0 || num_sets == -EINVAL) { + return 0; + } else if (num_sets < 0) { + dev_err(dev, "%pfwP: failed to read file set list: %d\n", + function_node, num_sets); + return num_sets; + } + + filesets_list = kcalloc(num_sets, sizeof(u32), GFP_KERNEL); + if (!filesets_list) + return -ENOMEM; + + fwnode_property_read_u32_array(function_node, "mipi-sdca-file-set-id-list", + filesets_list, num_sets); + + sets = devm_kcalloc(dev, num_sets, sizeof(struct sdca_fdl_set), GFP_KERNEL); + if (!sets) + return -ENOMEM; + + for (i = 0; i < num_sets; i++) { + u32 *fileset_entries __free(kfree) = NULL; + struct sdca_fdl_set *set = &sets[i]; + struct sdca_fdl_file *files; + int num_files, num_entries; + + snprintf(fileset_name, sizeof(fileset_name), + "mipi-sdca-file-set-id-0x%X", filesets_list[i]); + + num_entries = fwnode_property_count_u32(function_node, fileset_name); + if (num_entries <= 0) { + dev_err(dev, "%pfwP: file set %d missing entries: %d\n", + function_node, filesets_list[i], num_entries); + return -EINVAL; + } else if (num_entries % mult_fileset != 0) { + dev_err(dev, "%pfwP: file set %d files not multiple of %d\n", + function_node, filesets_list[i], mult_fileset); + return -EINVAL; + } + + dev_dbg(dev, "fileset: %#x\n", filesets_list[i]); + + files = devm_kcalloc(dev, num_entries / mult_fileset, + sizeof(struct sdca_fdl_file), GFP_KERNEL); + if (!files) + return -ENOMEM; + + fileset_entries = kcalloc(num_entries, sizeof(u32), GFP_KERNEL); + if (!fileset_entries) + return -ENOMEM; + + fwnode_property_read_u32_array(function_node, fileset_name, + fileset_entries, num_entries); + + for (j = 0, num_files = 0; j < num_entries; num_files++) { + struct sdca_fdl_file *file = &files[num_files]; + + file->vendor_id = fileset_entries[j++]; + file->file_id = fileset_entries[j++]; + file->fdl_offset = fileset_entries[j++]; + + dev_dbg(dev, "file: %#x, vendor: %#x, offset: %#x\n", + file->file_id, file->vendor_id, file->fdl_offset); + } + + set->id = filesets_list[i]; + set->num_files = num_files; + set->files = files; + } + + function->fdl_data.swft = sdw->sdca_data.swft; + function->fdl_data.num_sets = num_sets; + function->fdl_data.sets = sets; + + return 0; +} + /** * sdca_parse_function - parse ACPI DisCo for a Function * @dev: Pointer to device against which function data will be allocated. + * @sdw: SoundWire slave device to be processed. * @function_desc: Pointer to the Function short descriptor. * @function: Pointer to the Function information, to be populated. * * Return: Returns 0 for success. */ -int sdca_parse_function(struct device *dev, +int sdca_parse_function(struct device *dev, struct sdw_slave *sdw, struct sdca_function_desc *function_desc, struct sdca_function_data *function) { @@ -1947,14 +2132,20 @@ int sdca_parse_function(struct device *dev, if (!ret) function->busy_max_delay = tmp; - dev_info(dev, "%pfwP: name %s delay %dus\n", function->desc->node, - function->desc->name, function->busy_max_delay); + ret = fwnode_property_read_u32(function_desc->node, + "mipi-sdca-function-reset-max-delay", &tmp); + if (!ret) + function->reset_max_delay = tmp; + + dev_dbg(dev, "%pfwP: name %s busy delay %dus reset delay %dus\n", + function->desc->node, function->desc->name, + function->busy_max_delay, function->reset_max_delay); ret = find_sdca_init_table(dev, function_desc->node, function); if (ret) return ret; - ret = find_sdca_entities(dev, function_desc->node, function); + ret = find_sdca_entities(dev, sdw, function_desc->node, function); if (ret) return ret; @@ -1966,10 +2157,59 @@ int sdca_parse_function(struct device *dev, if (ret < 0) return ret; + ret = find_sdca_filesets(dev, sdw, function_desc->node, function); + if (ret) + return ret; + return 0; } EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); +const char *sdca_find_terminal_name(enum sdca_terminal_type type) +{ + switch (type) { + case SDCA_TERM_TYPE_LINEIN_STEREO: + return SDCA_TERM_TYPE_LINEIN_STEREO_NAME; + case SDCA_TERM_TYPE_LINEIN_FRONT_LR: + return SDCA_TERM_TYPE_LINEIN_FRONT_LR_NAME; + case SDCA_TERM_TYPE_LINEIN_CENTER_LFE: + return SDCA_TERM_TYPE_LINEIN_CENTER_LFE_NAME; + case SDCA_TERM_TYPE_LINEIN_SURROUND_LR: + return SDCA_TERM_TYPE_LINEIN_SURROUND_LR_NAME; + case SDCA_TERM_TYPE_LINEIN_REAR_LR: + return SDCA_TERM_TYPE_LINEIN_REAR_LR_NAME; + case SDCA_TERM_TYPE_LINEOUT_STEREO: + return SDCA_TERM_TYPE_LINEOUT_STEREO_NAME; + case SDCA_TERM_TYPE_LINEOUT_FRONT_LR: + return SDCA_TERM_TYPE_LINEOUT_FRONT_LR_NAME; + case SDCA_TERM_TYPE_LINEOUT_CENTER_LFE: + return SDCA_TERM_TYPE_LINEOUT_CENTER_LFE_NAME; + case SDCA_TERM_TYPE_LINEOUT_SURROUND_LR: + return SDCA_TERM_TYPE_LINEOUT_SURROUND_LR_NAME; + case SDCA_TERM_TYPE_LINEOUT_REAR_LR: + return SDCA_TERM_TYPE_LINEOUT_REAR_LR_NAME; + case SDCA_TERM_TYPE_MIC_JACK: + return SDCA_TERM_TYPE_MIC_JACK_NAME; + case SDCA_TERM_TYPE_STEREO_JACK: + return SDCA_TERM_TYPE_STEREO_JACK_NAME; + case SDCA_TERM_TYPE_FRONT_LR_JACK: + return SDCA_TERM_TYPE_FRONT_LR_JACK_NAME; + case SDCA_TERM_TYPE_CENTER_LFE_JACK: + return SDCA_TERM_TYPE_CENTER_LFE_JACK_NAME; + case SDCA_TERM_TYPE_SURROUND_LR_JACK: + return SDCA_TERM_TYPE_SURROUND_LR_JACK_NAME; + case SDCA_TERM_TYPE_REAR_LR_JACK: + return SDCA_TERM_TYPE_REAR_LR_JACK_NAME; + case SDCA_TERM_TYPE_HEADPHONE_JACK: + return SDCA_TERM_TYPE_HEADPHONE_JACK_NAME; + case SDCA_TERM_TYPE_HEADSET_JACK: + return SDCA_TERM_TYPE_HEADSET_JACK_NAME; + default: + return NULL; + } +} +EXPORT_SYMBOL_NS(sdca_find_terminal_name, "SND_SOC_SDCA"); + struct sdca_control *sdca_selector_find_control(struct device *dev, struct sdca_entity *entity, const int sel) |
