diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 92d76568e9e751..230571cc98f3f8 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -794,22 +794,23 @@ static int sdw_assign_device_num(struct sdw_slave *slave) return 0; } -void sdw_extract_slave_id(struct sdw_bus *bus, - u64 addr, struct sdw_slave_id *id) +void sdw_extract_slave_id(u64 addr, struct sdw_slave_id *id) { - dev_dbg(bus->dev, "SDW Slave Addr: %llx\n", addr); - id->sdw_version = SDW_VERSION(addr); id->unique_id = SDW_UNIQUE_ID(addr); id->mfg_id = SDW_MFG_ID(addr); id->part_id = SDW_PART_ID(addr); id->class_id = SDW_CLASS_ID(addr); +} +EXPORT_SYMBOL(sdw_extract_slave_id); - dev_dbg(bus->dev, +void sdw_debug_log_slave_id(struct device *dev, const struct sdw_slave_id *id) +{ + dev_dbg(dev, "SDW Slave class_id 0x%02x, mfg_id 0x%04x, part_id 0x%04x, unique_id 0x%x, version 0x%x\n", id->class_id, id->mfg_id, id->part_id, id->unique_id, id->sdw_version); } -EXPORT_SYMBOL(sdw_extract_slave_id); +EXPORT_SYMBOL(sdw_debug_log_slave_id); bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave) { @@ -862,7 +863,8 @@ static int sdw_program_device_num(struct sdw_bus *bus, bool *programmed) ((u64)buf[2] << 24) | ((u64)buf[1] << 32) | ((u64)buf[0] << 40); - sdw_extract_slave_id(bus, addr, &id); + sdw_extract_slave_id(addr, &id); + sdw_debug_log_slave_id(bus->dev, &id); found = false; /* Now compare with entries */ diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h index 44e4f51939176f..f1b4a493f1eb6c 100644 --- a/drivers/soundwire/bus.h +++ b/drivers/soundwire/bus.h @@ -19,8 +19,6 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus) #endif int sdw_of_find_slaves(struct sdw_bus *bus); -void sdw_extract_slave_id(struct sdw_bus *bus, - u64 addr, struct sdw_slave_id *id); int sdw_slave_add(struct sdw_bus *bus, struct sdw_slave_id *id, struct fwnode_handle *fwnode); int sdw_master_device_add(struct sdw_bus *bus, struct device *parent, diff --git a/drivers/soundwire/qcom.c b/drivers/soundwire/qcom.c index 55678a30cd4a1e..f44dbae9c84471 100644 --- a/drivers/soundwire/qcom.c +++ b/drivers/soundwire/qcom.c @@ -662,7 +662,8 @@ static int qcom_swrm_enumerate(struct sdw_bus *bus) ((u64)buf1[2] << 24) | ((u64)buf1[1] << 32) | ((u64)buf1[0] << 40); - sdw_extract_slave_id(bus, addr, &id); + sdw_extract_slave_id(addr, &id); + sdw_debug_log_slave_id(bus->dev, &id); found = false; ctrl->clock_stop_not_supported = false; /* Now compare with entries */ diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c index e0c49cbcb1bab4..9e64124455c2b5 100644 --- a/drivers/soundwire/slave.c +++ b/drivers/soundwire/slave.c @@ -135,7 +135,8 @@ static bool find_slave(struct sdw_bus *bus, if (link_id != bus->link_id) return false; - sdw_extract_slave_id(bus, addr, id); + sdw_extract_slave_id(addr, id); + sdw_debug_log_slave_id(bus->dev, id); return true; } diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index f710e5932b4b23..506d65a36e3e76 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1089,13 +1089,15 @@ int sdw_bus_clk_stop(struct sdw_bus *bus); int sdw_bus_exit_clk_stop(struct sdw_bus *bus); int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id); -void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id); +void sdw_extract_slave_id(u64 addr, struct sdw_slave_id *id); bool is_clock_scaling_supported_by_slave(struct sdw_slave *slave); int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg); int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg); int sdw_bpt_send_sync(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg); +void sdw_debug_log_slave_id(struct device *dev, const struct sdw_slave_id *id); + #if IS_ENABLED(CONFIG_SOUNDWIRE) int sdw_stream_add_slave(struct sdw_slave *slave, @@ -1216,6 +1218,14 @@ static inline int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u return -EINVAL; } +static inline void sdw_extract_slave_id(u64 addr, struct sdw_slave_id *id) +{ +} + +static inline void sdw_debug_log_slave_id(struct device *dev, const struct sdw_slave_id *id) +{ +} + #endif /* CONFIG_SOUNDWIRE */ /** diff --git a/include/sound/soc.h b/include/sound/soc.h index f46b2bc2a022bf..e493e955c51bd4 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -469,6 +469,10 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, const char *driver_name); struct snd_soc_component *snd_soc_lookup_component_by_name(const char *component_name); +typedef int (*snd_soc_component_walk_fn)(struct snd_soc_component *component, void *context); +struct snd_soc_component *snd_soc_lookup_component_walk(snd_soc_component_walk_fn cb, + void *context); + int soc_new_pcm(struct snd_soc_pcm_runtime *rtd); #ifdef CONFIG_SND_SOC_COMPRESS int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd); diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index 9b28e9aef4f1d6..dc46b03c6967f2 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -140,6 +140,9 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, int asoc_sdw_hw_free(struct snd_pcm_substream *substream); void asoc_sdw_shutdown(struct snd_pcm_substream *substream); +struct snd_soc_component *asoc_sdw_find_component(const struct asoc_sdw_dai_info *dai_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index); const char *asoc_sdw_get_codec_name(struct device *dev, const struct asoc_sdw_dai_info *dai_info, const struct snd_soc_acpi_link_adr *adr_link, diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 8a07ba2a29e5a7..86c0ed1a972c8b 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -1635,6 +1635,50 @@ static bool asoc_sdw_is_unique_device(const struct snd_soc_acpi_link_adr *adr_li return true; } +struct asoc_sdw_find_info { + const char *subname; + struct sdw_slave_id id; +}; + +static int asoc_sdw_find_component_cb(struct snd_soc_component *component, void *context) +{ + const struct asoc_sdw_find_info *info = context; + struct device *dev = component->dev; + + if (!is_sdw_slave(dev)) { + dev = component->dev->parent; + if (!dev || !is_sdw_slave(dev)) + return 0; + } + + if (sdw_compare_devid(dev_to_sdw_dev(dev), info->id) != 0) + return 0; + + if (info->subname && !strstr(component->name, info->subname)) + return 0; + + return 1; +} + +struct snd_soc_component *asoc_sdw_find_component(const struct asoc_sdw_dai_info *dai_info, + const struct snd_soc_acpi_link_adr *adr_link, + int adr_index) +{ + u64 adr = adr_link->adr_d[adr_index].adr; + struct asoc_sdw_find_info info; + struct snd_soc_component *component; + + sdw_extract_slave_id(adr, &info.id); + info.subname = dai_info->codec_name; + + component = snd_soc_lookup_component_walk(asoc_sdw_find_component_cb, &info); + if (IS_ERR(component)) + return NULL; + + return component; +} +EXPORT_SYMBOL_NS(asoc_sdw_find_component, "SND_SOC_SDW_UTILS"); + static const char *_asoc_sdw_get_codec_name(struct device *dev, const struct snd_soc_acpi_link_adr *adr_link, int adr_index) @@ -1661,22 +1705,23 @@ const char *asoc_sdw_get_codec_name(struct device *dev, const struct snd_soc_acpi_link_adr *adr_link, int adr_index) { - if (dai_info->codec_name) { - struct snd_soc_component *component; - - component = snd_soc_lookup_component_by_name(dai_info->codec_name); - if (component) { - dev_dbg(dev, "%s found component %s for codec_name %s\n", - __func__, component->name, dai_info->codec_name); - return devm_kstrdup(dev, component->name, GFP_KERNEL); - } else { - dev_dbg(dev, "%s component %s is not registered yet\n", - __func__, dai_info->codec_name); - return ERR_PTR(-EPROBE_DEFER); - } + struct snd_soc_component *component; + + component = asoc_sdw_find_component(dai_info, adr_link, adr_index); + if (!component) { + dev_dbg(dev, "%s component for addr %013llx subname '%s' is not registered yet\n", + __func__, + adr_link->adr_d[adr_index].adr, + dai_info->codec_name); + return ERR_PTR(-EPROBE_DEFER); } - return _asoc_sdw_get_codec_name(dev, adr_link, adr_index); + dev_dbg(dev, "%s found component %s for adr %013llx subname '%s'\n", + __func__, component->name, + adr_link->adr_d[adr_index].adr, + dai_info->codec_name); + + return devm_kstrdup(dev, component->name, GFP_KERNEL); } EXPORT_SYMBOL_NS(asoc_sdw_get_codec_name, "SND_SOC_SDW_UTILS"); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 0023535adbe386..c4aa53b7795031 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -406,6 +406,39 @@ struct snd_soc_component *snd_soc_lookup_component_by_name(const char *component } EXPORT_SYMBOL_GPL(snd_soc_lookup_component_by_name); +/** + * snd_soc_lookup_component_walk - component lookup using callback. + * @cb: function to call for each component. + * @context: caller-defined value to be passed to callback function. Can + * be NULL. + * + * Iterate over snd_soc_component items, calling @cb for each, until @cb + * returns a non-zero value. The @context pointer is a value defined by the + * caller and is passed to @cb. + * + * Return: struct snd_soc_component* if @cb returned >0. + * ERR_PTR(-ENOENT) if @cb returned 0 on every call. + * ERR_PTR of value returned by @cb if @cb returned <0. + */ +struct snd_soc_component *snd_soc_lookup_component_walk(snd_soc_component_walk_fn cb, + void *context) +{ + struct snd_soc_component *component; + int ret; + + guard(mutex)(&client_mutex); + for_each_component(component) { + ret = (cb)(component, context); + if (ret > 0) + return component; + if (ret < 0) + return ERR_PTR(ret); + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL_GPL(snd_soc_lookup_component_walk); + struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link)