Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/sound/sdca.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines 65 to 69
int sdca_dev_register_functions(struct sdw_slave *slave);
void sdca_dev_unregister_functions(struct sdw_slave *slave);
Expand All @@ -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;
Expand Down
69 changes: 69 additions & 0 deletions sound/soc/intel/boards/sof_sdw.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#include <linux/soundwire/sdw_type.h>
#include <linux/soundwire/sdw_intel.h>
#include <sound/core.h>
#include <sound/sdca.h>
#include <sound/sdca_function.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "sof_sdw_common.h"
#include "../../codecs/rt711.h"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1011,12 +1031,60 @@ 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;
const char *codec_name = sof_end->codec_name;
int sdw_mic_num;
int k;

peripheral = sof_sdw_get_peripheral_by_codec_name(codec_name);
if (!peripheral) {
/*
* asoc_sdw_parse_sdw_endpoints() is already checked
* peripheral is not NULL, so this should never happen.
*/
dev_err(dev, "Can't get peripheral for codec %s\n",
sof_end->codec_name);
return -EINVAL;
}
Comment on lines +1048 to +1057

for (k = 0; k < peripheral->sdca_data.num_functions; k++) {
struct sdca_function_desc *function =
&peripheral->sdca_data.function[k];
char *tmp = name;

if (function->type != SDCA_FUNCTION_TYPE_SMART_MIC)
continue;

sdw_mic_num = sdca_get_mic_count(peripheral, function);
if (sdw_mic_num < 0) {
dev_dbg(dev, "%s mic count query failed: %d\n",
sof_end->codec_name, sdw_mic_num);
continue;
}
dev_dbg(dev, "%s mic num %d\n",
sof_end->codec_name, sdw_mic_num);
if (sdw_mic_num <= 0 || strstr(name, "ch"))
continue;

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);
Expand Down Expand Up @@ -1582,3 +1650,4 @@ MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
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");
106 changes: 106 additions & 0 deletions sound/soc/sdca/sdca_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,112 @@ 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 || num_entities > SDCA_MAX_ENTITY_COUNT) {
dev_err(&slave->dev,
"%pfwP: entity number %d is invalid for function type %u\n",
function_node, num_entities, 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 = "<unknown>";
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_dbg(&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);

fwnode_handle_put(entity_node);
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;
Expand Down
Loading