diff --git a/include/sound/sdca.h b/include/sound/sdca.h index 2bdf4e333e0449..61e4015f81547e 100644 --- a/include/sound/sdca.h +++ b/include/sound/sdca.h @@ -65,6 +65,7 @@ enum sdca_quirk { void sdca_lookup_functions(struct sdw_slave *slave); void sdca_lookup_swft(struct sdw_slave *slave); void sdca_lookup_interface_revision(struct sdw_slave *slave); +int sdca_get_mic_count(struct sdw_slave *slave, struct sdca_function_desc *function); bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk); int sdca_dev_register_functions(struct sdw_slave *slave); void sdca_dev_unregister_functions(struct sdw_slave *slave); @@ -74,6 +75,10 @@ void sdca_dev_unregister_functions(struct sdw_slave *slave); static inline void sdca_lookup_functions(struct sdw_slave *slave) {} static inline void sdca_lookup_swft(struct sdw_slave *slave) {} static inline void sdca_lookup_interface_revision(struct sdw_slave *slave) {} +static inline int sdca_get_mic_count(struct sdw_slave *slave, struct sdca_function_desc *function) +{ + return 0; +} static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk) { return false; diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index d5383c8dcdf099..21fddc8777e2bf 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include #include "sof_sdw_common.h" #include "../../codecs/rt711.h" @@ -900,6 +903,23 @@ static const struct snd_soc_ops sdw_ops = { static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; +static struct sdw_slave *sof_sdw_get_peripheral_by_codec_name(const char *codec_name) +{ + struct snd_soc_component *component; + + component = snd_soc_lookup_component_by_name(codec_name); + if (!component) + return NULL; + + if (is_sdw_slave(component->dev)) + return dev_to_sdw_dev(component->dev); + + if (component->dev->parent && is_sdw_slave(component->dev->parent)) + return dev_to_sdw_dev(component->dev->parent); + + return NULL; +} + static int create_sdw_dailink(struct snd_soc_card *card, struct asoc_sdw_dailink *sof_dai, struct snd_soc_dai_link **dai_links, @@ -1011,12 +1031,46 @@ static int create_sdw_dailink(struct snd_soc_card *card, codecs[j].name = sof_end->codec_name; codecs[j].dai_name = sof_end->dai_info->dai_name; + if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC && mach_params->dmic_num > 0) { dev_warn(dev, "Both SDW DMIC and PCH DMIC are present, if incorrect, please set kernel params snd_sof_intel_hda_generic dmic_num=0 to disable PCH DMIC\n"); } j++; + + if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC) { + struct sdw_slave *peripheral; + int sdw_mic_num; + int k; + + peripheral = sof_sdw_get_peripheral_by_codec_name(sof_end->codec_name); + if (!peripheral) { + /* This should not happan. Just a Paranoia check */ + dev_err(dev, "failed to get peripheral for codec %s\n", + sof_end->codec_name); + return -EINVAL; + } + + for (k = 0; k < peripheral->sdca_data.num_functions; k++) { + if (peripheral->sdca_data.function[k].type != SDCA_FUNCTION_TYPE_SMART_MIC) + continue; + + sdw_mic_num = sdca_get_mic_count(peripheral, &peripheral->sdca_data.function[k]); + dev_dbg(dev, "%s mic num %d\n", sof_end->codec_name, sdw_mic_num); + if (sdw_mic_num > 0) { + char *tmp = name; + name = devm_kasprintf(dev, GFP_KERNEL, "%s-%dch", name, sdw_mic_num); + if (!name) + return -ENOMEM; + + devm_kfree(dev, tmp); + break; + } + } + + } + } WARN_ON(i != num_cpus || j != num_codecs); @@ -1582,3 +1636,4 @@ MODULE_AUTHOR("Pierre-Louis Bossart "); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); +MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 77940bd6b33c95..796c5f7daaa1c2 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -200,6 +200,110 @@ void sdca_lookup_functions(struct sdw_slave *slave) } EXPORT_SYMBOL_NS(sdca_lookup_functions, "SND_SOC_SDCA"); +int sdca_get_mic_count(struct sdw_slave *slave, struct sdca_function_desc *function) +{ + struct fwnode_handle *function_node; + u32 *entity_list __free(kfree) = NULL; + u32 transducer_count = 0; + u32 terminal_type; + int num_entities; + int ret; + int i; + + if (!function || !function->node) + return -EINVAL; + + function_node = function->node; + + num_entities = fwnode_property_count_u32(function_node, + "mipi-sdca-entity-id-list"); + if (num_entities <= 0) { + dev_err(&slave->dev, + "%pfwP: no entity list found for function type %u\n", + function_node, function->type); + return -EINVAL; + } + + entity_list = kcalloc(num_entities, sizeof(*entity_list), GFP_KERNEL); + if (!entity_list) + return -ENOMEM; + + ret = fwnode_property_read_u32_array(function_node, + "mipi-sdca-entity-id-list", + entity_list, num_entities); + if (ret) { + dev_err(&slave->dev, + "%pfwP: failed to read entity id list for function type %u: %d\n", + function_node, function->type, ret); + return ret; + } + + for (i = 0; i < num_entities; i++) { + struct fwnode_handle *entity_node; + const char *entity_label = ""; + u32 entity_type; + char entity_property[SDCA_PROPERTY_LENGTH]; + + /* DisCo uses upper-case for hex numbers */ + snprintf(entity_property, sizeof(entity_property), + "mipi-sdca-entity-id-0x%X-subproperties", entity_list[i]); + + entity_node = fwnode_get_named_child_node(function_node, entity_property); + if (!entity_node) { + dev_dbg(&slave->dev, "%pfwP: missing entity node %s\n", + function_node, entity_property); + continue; + } + + fwnode_property_read_string(entity_node, "mipi-sdca-entity-label", + &entity_label); + + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-entity-type", + &entity_type); + if (ret) { + dev_info(&slave->dev, + "SDCA function %s (type %u adr 0x%x): entity 0x%x label %s type missing\n", + function->name, function->type, function->adr, + entity_list[i], entity_label); + goto put_entity_node; + } + + dev_dbg(&slave->dev, + "SDCA function %s (type %u adr 0x%x): entity 0x%x label %s type 0x%x\n", + function->name, function->type, function->adr, + entity_list[i], entity_label, entity_type); + + if (entity_type == SDCA_ENTITY_TYPE_IT) { + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-terminal-type", + &terminal_type); + if (ret) + goto put_entity_node; + + if (terminal_type != SDCA_TERM_TYPE_MICROPHONE_TRANSDUCER && + terminal_type != SDCA_TERM_TYPE_MICROPHONE_ARRAY_TRANSDUCER) + goto put_entity_node; + + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-terminal-transducer-count", + &transducer_count); + if (ret) + goto put_entity_node; + + dev_info(&slave->dev, + "SDCA function %s entity %s: mipi-sdca-terminal-type=%#x mipi-sdca-terminal-transducer-count=%u\n", + function->name, entity_label, terminal_type, transducer_count); + break; + } + +put_entity_node: + fwnode_handle_put(entity_node); + } + + return transducer_count; +} +EXPORT_SYMBOL_NS(sdca_get_mic_count, "SND_SOC_SDCA"); + struct raw_init_write { __le32 addr; u8 val;